Weakening `private` to file scope
titzer opened this issue · 4 comments
I am thinking of making a significant change to the meaning of the private
keyword. Currently, private
indicates that a field or method is only visible within the scope of the class or component or variant that it was declared in. Subclasses, for example, would not have access.
However, I recently added a new meaning for this keyword where private
makes a type local to the namespace of a file (rather than the program).
That just gave me an idea: if the meaning of private
always meant that the field, method, or type is only visible in the file, including subclasses in this file, other classes in this file, and even top-level methods and initializers in this file, then several problems are solved at once:
- Subclasses can access private state of superclasses, while outside classes cannot, just like Java's
protected
. - Utility methods declared inside the file that accompany the definition (which in Java are often
static
methods of the class), can access private state, e.g. to more efficiently manipulate objects using internal representation knowledge. - A constructor could be marked as private, making it possible to only construct objects through utility methods that are explicitly exposed outside the file.
Example for utility methods:
class Vector<T> {
private var array: Array<T>;
private def var length: int;
...
}
// public utility methods to construct vectors.
component Vectors {
def concat<T>(x: Vector<T>, y: Vector<T>) -> Vector<T> {
... internal direct uses of fields {x.array} and {y.length} ...
}
}
Example for protected
emulation.
file: MyClass.v3
-------------------
class MyClass {
private def internalMethod();
}
class MySubClass extends MyClass {
def publicMethod() {
internalMethod(); // visible here because in same file
}
}
file: Other.v3
------------------
var x = MySubClass.new();
var d = x.internalMethod(); // not visible here, not even in a subclass defined here.
I really like this idea because it means:
- No
friend
classes for spooky-action at a distance: private shenanigans must be in same file! - No code-safari hunting for all the uses of a
private
field/method/class: they are in this one file! - Allows some OO patterns (like
super
method) without falling prey to fragile base class problems: all classes that have tighter contracts are in the same file! - ONE MEANING: a
private
declaration is only visible in the file it is declared in.
Wdyt?
So like static
in C/C++, but a bit nicer. Sounds good. One thought is if an import or module system is ever added, then it may be useful to have module-private functions/classes as well (something like Rust's pub(super)
). But maybe that overcomplicates the design.
I've implemented this in a branch but haven't merged it yet because I am thinking about how it may slightly surprise some programmers.
E.g. a Java expert might be slightly surprised that private
applies to the whole file (i.e. wider scope than assumed). However, I think this is alright because the Java tendency to split classes one-per-file means this isn't much different. I don't think it's too jarring if Virgil has a few more classes and related utility code per file, and it may even be cleaner for reasons above.
So I'll probably land this soon.
I've implemented this in a branch but haven't merged it yet because I am thinking about how it may slightly surprise some programmers.
Just need clear, concise documentation, I would say. static
in C != static
in Java for example and Java experts who came from C have managed.