I like the idea you presented for access control below public and I appreciate your efforts to have a good discussion about this a lot. Reading such discussions can also be very helpful to understand the complexity and the details of a topic to people not jet used to it (like me).
I have some questions about concretely the ideas you presented above.
I guess thats a (module)private
in your description (that's not explicitly specified or I didn't see it), not a "pure" type restricted access control solution, such that I could also access these private members from an outside module, if I am extending the type.
It looks like we were mixing two different access control systems here, restricting access based on modules and restricting access based on types. From my limited perspective, it seems like doing this isn't uncommon in other languages, but it might add unnecessary (learning) complexity.
To demonstrate what I want to say, I am going to describe the most extreme form of having these two access control principles mixed together, however I don't want to actually have this:
Theoretical description
Basically this means having type and "whole scope" access control on all levels, with these granularities:
- type:
- type (access restricted to a type)
- global (access not restricted to a type (visible in the whole module/file/etc.))
- scopes:
- file
- module
- universe (accessible from everywhere)
Then if these could be arbitrarily combined, we would have
access-restriction(file, type)
, this is (file)private
from this thread or the current private
access-restriction(file, global)
, this is (file)internal
or fileprivate
access-restriction(module, type)
, this is the new default private
in this thread, the missing access control level to separate some (somehow interconnected) functionality of one type into two files
access-restriction(module, global)
, this is the current internal
access-restriction(universe, type)
, this is another level that is similar to protected
, but not the same because it has nothing to do with subclasses. Elements of a type declared this way will only be accessible in extensions of this type. This might be useful for sharing some utility methods also useful in other context, but allowing this might also be a non-goal
access-restriction(universe, global)
, this is the current public
.
open
isn't covered at all here. It could be added with a third "subclass" (which would mean overridable in subclass) case as additional type access view. If we allowed this case with all three scope cases, we would gain three additional combinations with open-like features for file and module visibility.
Since we have open
and public
, but no ability to express the same thing at the internal
level, I would not know why we shouldn't have the type visibility only on the internal level (and the file level, where we already have it) in general, except that it clearly destroys the easy to understand subset relationship between access levels.
To keep the subset relationship between the access modifiers, we could move the new private
one step up, above "fileinternal
". private
would then allow access from the file a type is declared in and in extensions of this type inside the same module.
I think both (file)internal
and (file)private
will still have use cases for people that like to pack multiple types inside one huge file because they like to do this, like I like not to do this, but spread one type through multiple files. The current access control system does indeed provide more functionality for the people putting everything inside one file. Similarly it isn't possible to define new overridable methods in an extension of a class. Certainly there is a reason for this (and I would really like to know it!).
In my opinion we are missing a feature to express an access restriction to extensions of a type inside a module, because it is possible to split functionality of a single type into multiple files with extensions.
As far as I know, this isn't a misuse of extensions, but a valid use case. Whether it is a good idea to organise things into multiple files or not is another thing and actually something every team or programmer has to decide on it's own for it's own code. Swift makes both possible.