mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-01 21:21:10 +00:00
191 lines
4.1 KiB
Markdown
191 lines
4.1 KiB
Markdown
# Visibility
|
|
|
|
Erg variables have the concept of __visibility__.
|
|
All variables we have seen so far are called __private variables__. These are variables that are invisible to the outside world.
|
|
For example, a private variable defined in the `foo` module cannot be referenced from another module.
|
|
|
|
```erg
|
|
# foo.er
|
|
x = "this is an invisible variable"
|
|
```
|
|
|
|
```erg
|
|
# bar.er
|
|
foo = import "foo"
|
|
foo.x # AttributeError: Module 'foo' has no attribute 'x' ('x' is private)
|
|
```
|
|
|
|
In contrast, there is also a __public variable__, which can be referenced externally.
|
|
Public variables are defined with `.`.
|
|
|
|
```erg
|
|
# foo.er
|
|
.x = "this is a visible variable"
|
|
```
|
|
|
|
```erg
|
|
# bar.er
|
|
foo = import "foo"
|
|
assert foo.x == "this is a visible variable"
|
|
```
|
|
|
|
Private variables do not need to be marked with anything, but can be marked with `::` or `self::` (or `Self::` for types, etc.) to make them explicitly private. A module can also be `module::`.
|
|
|
|
```erg
|
|
::x = "this is an invisible variable"
|
|
assert ::x == x
|
|
assert self::x == ::x
|
|
assert module::x == ::x
|
|
```
|
|
|
|
In the context of mere sequential execution, private variables are almost synonymous with local variables. They can be referenced from inner scope.
|
|
|
|
```erg
|
|
::x = "this is a private variable"
|
|
y =
|
|
x + 1 # exactly module::x
|
|
```
|
|
|
|
The `::` allows you to distinguish between variables with the same name in a scope.
|
|
Specify the scope of the variable you want to reference on the left. For the top level, specify `module`.
|
|
If not specified, the innermost variable is referenced as in the normal case.
|
|
|
|
```erg
|
|
::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 scope of an anonymous subroutine, `self` specifies its own scope.
|
|
|
|
```erg
|
|
x = 0
|
|
f = x ->
|
|
log module::x, self::x
|
|
f 1 # 0 1
|
|
```
|
|
|
|
`::` is also responsible for accessing private instance attributes.
|
|
|
|
```erg
|
|
x = 0
|
|
C = Class {x = Int}
|
|
C.
|
|
# Top-level x is referenced (warns to make it module::x)
|
|
f1 self = x
|
|
# x of instance attribute is referenced
|
|
f2 self = self::x
|
|
```
|
|
|
|
## Visibility in external modules
|
|
|
|
A class defined in one module can actually define methods from an external module as well.
|
|
|
|
```erg
|
|
## foo.er
|
|
.Foo = Class()
|
|
```
|
|
|
|
```erg
|
|
# 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 can only be used within that module.
|
|
Externally defined private methods can be referenced by methods of the `Foo` class only within the defining module.
|
|
Public methods are exposed outside the class, but not to outside the module.
|
|
|
|
```erg
|
|
# baz.er.
|
|
{Foo; ...} = import "foo"
|
|
|
|
foo = Foo.new()
|
|
foo.public() # AttributeError: 'Foo' has no attribute 'public' ('public' is defined in module 'bar')
|
|
```
|
|
|
|
Also, you cannot define a method on the type you are re-exporting.
|
|
This is to avoid confusion when a method is found or not found depending on the module from which it is imported.
|
|
|
|
```erg
|
|
# bar.er
|
|
{.Foo; ...} = import "foo"
|
|
|
|
.Foo::
|
|
private self = pass # Error
|
|
.Foo.
|
|
Foo:: public self = self::private() # Error
|
|
```
|
|
|
|
If you want to do something like this, define a [patch](./type/07_patch.md).
|
|
|
|
```erg
|
|
# bar.er.
|
|
{Foo; ...} = import "foo"
|
|
|
|
FooImpl = Patch Foo
|
|
FooImpl::
|
|
private self = pass
|
|
FooImpl.
|
|
public self = self::private()
|
|
```
|
|
|
|
```erg
|
|
# 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.
|
|
|
|
``` erg
|
|
# 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
|
|
```
|
|
|
|
``` erg
|
|
foo = import "foo"
|
|
_ = foo.record.a.x # VisibilityError
|
|
_ = foo.record.a.y # VisibilityError
|
|
_ = foo.record.a.z # OK
|
|
```
|
|
|
|
<p align='center'>
|
|
<a href='./18_memory_management.md'>Previous</a> | <a href='./20_naming_rule.md'>Next</a>
|
|
</p>
|