# Visibility Erg variables have the concept of __visibility__. All the variables we've seen so far are called __private variables__. This is an externally invisible variable. For example, a private variable defined in the `foo` module cannot be referenced by another module. ```python # foo.er x = "this is an invisible variable" ``` ```python # bar.er foo = import "foo" foo.x # AttributeError: Module 'foo' has no attribute 'x' ('x' is private) ``` On the other hand, there are also __public variables__, which can be referenced from the outside. Public variables are defined with `.`. ```python # foo.er .x = "this is a visible variable" ``` ```python # bar.er foo = import "foo" assert foo.x == "this is a visible variable" ``` You don't need to add anything to private variables, but you can also add `::` or `self::` (`Self::` for types etc.) to indicate that they are private. increase. It can also be `module::` if it is a module. ```python ::x = "this is an invisible variable" assert ::x == x assert self ::x == ::x assert module::x == ::x ``` In the context of purely sequential execution, private variables are almost synonymous with local variables. It can be referenced from the inner scope. ```python ::x = "this is a private variable" y = x + 1 # exactly module::x ``` By using `::`, you can distinguish variables with the same name within the scope. Specify the scope of the variable you want to refer to on the left. Specify `module` for the top level. If not specified, the innermost variable is referenced as usual. ```python ::x = 0 assert x == 0 y = ::x = 1 assert x == 1 z = ::x = 2 assert ::x == 2 assert z::x == 2 assert y::x == 1 assert module::x == 0 ``` In the anonymous subroutine scope, `self` specifies its own scope. ```python x = 0 f = x -> log module::x, self::x f1# 0 1 ``` `::` is also responsible for accessing private instance attributes. ```python x = 0 C = Class {x = Int} C. # Top-level x is referenced (warning to use module::x) f1 self = x # instance attribute x is referenced f2 self = self::x ``` ## Visibility in external modules A class defined in one module can actually define methods from an external module. ```python # foo.er .Foo = Class() ``` ```python # bar.er {Foo; ...} = import "foo" Foo:: private self = pass Foo. public self = self::private() .f() = foo = Foo.new() foo.public() foo::private() # AttributeError ``` However, both of those methods are only available within that module. Private methods defined externally are visible to methods of the `Foo` class only within the defining module. Public methods are exposed outside the class, but not outside the module. ```python # baz.er {Foo; ...} = import "foo" foo = Foo.new() foo.public() # AttributeError: 'Foo' has no attribute 'public' ('public' is defined in module 'bar') ``` Also, methods cannot be defined in the type to be re-exported. This is to avoid confusion about methods being found or not found depending on the module they are imported from. ```python # bar.er {.Foo; ...} = import "foo" .Foo:: private self = pass # Error Foo. public self = self::private() # Error ``` If you want to do something like this, define a [patch](./type/07_patch.md). ```python # bar.er {Foo; ...} = import "foo" FooImpl = Patch Foo FooImpl :=: private self = pass Foo Impl. public self = self::private() ``` ```python # baz.er {Foo; ...} = import "foo" {FooImpl; ...} = import "bar" foo = Foo.new() foo.public() ``` ## restricted public variables Variable visibility is not limited to complete public/private. You can also publish with restrictions. ```python # foo.er .record = { .a = { .(.record)x = 0 .(module)y = 0 .z = 0 } _ = .a.x # OK _ = .a.y # OK _ = .a.z # OK } _ = .record.a.x # VisibilityError _ = .record.a.y # OK _ = .record.a.z # OK ``` ```python foo = import "foo" _ = foo.record.a.x # VisibilityError _ = foo.record.a.y # VisibilityError _ = foo.record.a.z # OK ```

Previous | Next