Visibility
The visibility of a feature defines where this feature can be accessed.
Scopes
A block consists of indented statements or statements enclosed by
braces { }
.
A scope is defined by a block. Scopes can be nested. For example the declaration of an inner feature is a statement in a surrounding block or the block in an if-statement is nested in the block that contains the if statement.
Unqualified Visibility
Routines
The unqualified visibility of a routine determines where this routine can be
called without a qualifying target t as in t.f
. A routine
f declared in scope s is visible for an unqualified call in s itself, all nested
scopes of s and all inner routines declared in the same scope s or in any nested
scope within s:
Fields
Compared to routines, fields are not visible for unqualified calls before their declaration:
Assignment Visibility
Unqualified mutable fields can be the target of an assignment whenever the field is visible for an unqualified call.
Masking
Masking fields, sometimes also called variable shadowing is not allowed in fuzion.
Features declared in inner Blocks
Features declared in inner blocks have visibility restrictions similar to those declared in inner features:
The visibility in loops is a bit more complicated, as shown in this example:
In a loop, within the for-block, index variables that are not iterators can
be accessed after their declaration and in the next-part of their declaration
(after the comma). Index variables are accessible in the while- and
until-blocks. Features declared in the while-block are also accessible in the
until-block. The else block can access all index variables before the first
iterator index variable (one that uses in
in the for-block)
The reason for this complex visibility is that it is guaranteed that a for-block is executed fully before the while block is entered. Additionally, the until-block can only be entered after the while block was fully executed.
On the other hand, the else block may be entered as soon as an iterator index variable reaches the end of the iterated set, so only previously declared index variables are guaranteed to be set.
Qualified Visibility
The qualified visibility determines if a feature f
is visible via a qualified access target.f
.
Qualified Call Visibility
TBD:
- features within one source code file should probably be fully visible for qualified accesses within the same file
- features in another source code file should be made visible, e.g., by a
keyword
public
, to be visible for qualified calls - features could be made visible to specific other friend features
via
visible to friend
or, if all subclasses of friend should be included, viavisible to * : friend
or a similar syntax.
Qualified Assignment Visibility
Qualified assignments are not allowed:
Even qualified assignments to masked outer fields are not allowed:
Module Visibility
A feature declared in another module is visible to other modules only if it
is exported from the modules. TBD: Need to decide how to do this, mark
it export
or similar.
An exported feature f declared in scope s of a module m is visible for an unqualified call in another module m2 if that call happens in a scope s2 that is an inner scope of s and it was not masked.
Unqualified Visibility
Example: In module A:
export a { export x { } export b { export y { } public z { } } public c { export y { } // *** illegal, compiler error: cannot export y since outer c is not exported public z { } } }
In module B:
a.b.new_feature_in_b { // ... x and y are visible here, c and z are not ... } a.c.new_feature_in_b // *** illegal, compiler error: c not exported { // ... }
Qualified Visibility
Qualified accesses to features of another module are restricted to the features that are exported from that module.
Module Assignment Visibility
No fields declared in another module are visible as the target of an assignment in another module.
Visibility for Inheritance
Some languages treat visibility in heirs of a class differently. Java for example knows protected
members and has just
introduced sealed classes JEP 360.
For Fuzion, the question is whether it would be useful to make a feature visible as a type without allowing calls to the feature, in particular without allowing calls in an inheritance clause.
TBW: Need to decide if this is important enough and if so, do we need specific language support for this or can this be modelled differently (e.g., by adding a unit type argument to a feature that is made visible only to the permitted heirs)?
Visibility of Types vs. Constructors
In some situations, a type that is defined by a constructor feature should be accessible, but not the constructor itself, e.g.,
Here, we might want to make the type dice.face
visible so that one can declare
sum(toss1, toss2 dice.face) => toss1.n + toss2.n
while it should be disallowed to create a new face as in
cheat := dice.face 7
Visibility Modifiers in other languages
Java
private
for local visibility,
protected
for local plus sub-class visibility,
for package visibility,
public
for unrestricted visibility.
Perl
Perls uses our
, my
and local
to extend
the scope of variables in somewhat confusing ways. our
and my
are, however, short and might be useful as simple
markers.
Oberon
Oberon replaces the def-files in Modula-2 by a marker *
for
everything that is exported.
C
C uses .h files to define what is accessible and static
to make
a declaration inaccessible by other source files.
Eiffel
Eiffel uses a clients clause in a feature declaration. The clients clause
explicitly lists the classes to which a feature is to be visible, while
classes ANY
and NONE
handle the special cases of all
classes or private features.
Visibility modifiers in Fuzion
The idea is to have three modifiers priv
, module
and pub
to modify the visibility for calls and when used as type.
Since priv
is also the default visibility, the priv
modifier can be omitted to have private (file local only) visibility.
Visibility
Modifier
|
Current file | Current module | Other module |
---|---|---|---|
priv or |
✅ Yes | ❌ No | ❌ No |
module |
✅ Yes | ✅ Yes | ❌ No |
pub |
✅ Yes | ✅ Yes | ✅ Yes |
When a different visibility for a type declared by a constructor is desired,
a variant of type:priv
, type:module
and type:pub
can be added to modify the type visibility of constructors.
Visibility
Modifier
|
For calls | As types | ||||
---|---|---|---|---|---|---|
Current file | Current module | Other module | Current file | Current module | Other module | |
priv , priv type:priv , type:priv or |
✅ Yes | ❌ No | ❌ No | ✅ Yes | ❌ No | ❌ No |
priv type:module or type:module |
✅ Yes | ❌ No | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
priv type:pub or type:pub |
✅ Yes | ❌ No | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
module type:priv |
✅ Yes | ✅ Yes | ❌ No | ✅ Yes | ❌ No | ❌ No |
module or module type:module |
✅ Yes | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
module type:pub |
✅ Yes | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
pub type:priv |
✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
pub type:module |
✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
pub or pub type:pub |
✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
Visibility and feature inheritance
In case complex
is exported as a public part of a module, we
might not want to expose the fact that it inherits from trigo
for
implementation purposes, so we can inherit in private: