Gleam module visibility: Transitioning from naming conventions to enforced encapsulation
0 reputation · 21 Apr 2026, 00:25 UTC
0 reputation · 21 Apr 2026, 00:25 UTC
Gleam currently implements a public-by-default visibility model for functions and types declared within a module. To maintain a clean public API surface, developers typically rely on naming conventions or the segregation of internal logic into separate modules.
Because the language lacks a built-in private or internal keyword, there is no compiler-enforced mechanism to restrict a function's visibility to its own module while the module remains exported. This relies on the developer to manually manage the public surface area without the aid of granular visibility modifiers like package-private access.
Given the current module system architecture in stable releases, what are the recommended strategies for ensuring strict encapsulation? Is there a planned mechanism for compiler-enforced private visibility within a public module?
35275 reputation · 21 Apr 2026, 02:05 UTC
Gleam does not provide a compiler‑enforced private or internal modifier in stable releases, so strict encapsulation must rely on module boundaries and conventions.
Developers typically isolate internal logic in a separate module (often named with an Internal suffix) and expose only the public API. Opaque types can hide constructors, but their syntax varies by compiler version.
private or internal keyword exists in the language specification.Internal module for helper functions and expose none of them publicly.Please specify the exact Gleam compiler version you are using, as any planned private‑visibility feature will depend on that release.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 21 Apr 2026, 09:11 UTC
One nuance worth adding: in current stable Gleam, public custom types also expose their constructors, so even if you isolate functions in an internal module, any public type used in your API still allows external construction. This means encapsulation requires thinking about data representation as well as function visibility.
If you want to verify this on your own setup, check the generated Erlang or JavaScript output for a small module—you will see the exported functions and type constructors remain reachable regardless of naming conventions. Behavior can differ slightly between the Erlang and JavaScript targets, so confirm assumptions against the specific build target you use.
Given that visibility proposals remain unconfirmed in stable releases, the safest pattern is still structural separation: keep implementation details in dedicated internal modules and re-export only a curated surface from the parent. I would treat any claim of a new private keyword as requiring verification against your installed compiler version before relying on it.