> On Feb 25, 2017, at 4:23 PM, Jonathan Hull <[email protected]> wrote:
> 
> 
>> On Feb 25, 2017, at 1:43 PM, Matthew Johnson via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>> 
>>> On Feb 25, 2017, at 3:27 PM, Kevin Nattinger via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>>> …
>>>> Additionally, the design allows ‘final’ to take any one of those 
>>>> visibility levels as a parameter, to indicate that the type should be 
>>>> treated as ‘final’ at and above the specified scope. Thus ‘final(public)’ 
>>>> prevents subclassing outside the module, while ‘final(internal)’ prevents 
>>>> it outside the ‘private’ scope. For consistency, ‘final(private)’ is also 
>>>> permitted, although it means the same thing as ‘final’ by itself.
>>> 
>>> I feel final(public) could be confusing given how we currently have 
>>> private(get/set). What about public(final)? That’s at least consistent with 
>>> current access syntax.
>> 
>> The syntax that most closely aligns with private(set) is internal(inherit).  
>> The parameter expresses a capability not a limitation and it is used with an 
>> access modifier that specifies the *maximum* access level that is allowed to 
>> have this capability.  `final` is also misleading in this context because it 
>> implies to most people that there are *no* subclasses (inside or outside the 
>> module).  
>> 
>> The only way to express `final` in Swift’s access control system would to 
>> have a `never` access modifier allowing you to say `never(inherit)`.  I can’ 
>> think of any other uses for an access level like this.  `final` is much more 
>> direct and is the term of art.  I don’t see a reason to change the spelling 
>> of `final` and parameterizing it doesn’t make any sense - if something is 
>> `final` it is `final` in *all* scopes.
> 
> hmm… ‘semifinal' for things that are closed outside the submodule?

The name that has usually been used for this is `closed`.  But no word that 
expresses a *restriction* is going to fit well into Swift’s access control 
system.  The approach of Swift’s access control system (which I believe to be 
the best approach) is to express an upper bound on a *capability*.  The basic 
capability is visibility of the symbol.  That model is extended by talking 
about specific things a user might *do* with that symbol and setting an upper 
bound on that specific use: `internal private(set)`.  `internal` is the bound 
on visibility and `private` is the bound on the ability to `set` the property.  

`closed` is most naturally expressed in this system as `public 
internal(inherit)`.  One interesting thing to observe is that `internal` is the 
default level of visibility. If we extend that default to capabilities as well 
as visibility the result is to give us exactly the behavior we want from a 
naked `public` annotation.  We want to require an annotation for exposing 
anything (a symbol *or* a capability) outside the module.  This means that 
`open` is really an alias for `public(inherit)` if we follow the principles 
underlying the model we have for access control.

Following this line of reasoning to its natural conclusion we can observe that 
the current interaction of `var` properties with access control *do not* follow 
the principles we have set forth for Swift.  `public` variables *automatically* 
have `public` getters violating the principle that `internal` is the default.  
We could fix this by requiring users to say `public(set)`.  I imagine there 
would be a lot of screaming in the short term if we proposed this.  But it 
would put Swift’s access control system on a more consistent and principled 
footing.  

I think there are three major reasons people have trouble with the current 
access control system.  The `private` / `fileprivate` name situation is an 
obvious one.  But I think perhaps more important is the fact that the system 
has idiosyncrasies such as introducing `open` rather than following the 
capability model of `set` (which would have resulted in `public(inherit)`).  
Another idiosyncrasy noted above is that `set` defaults to the level of the 
getter rather than `internal` (but bounded by visibility).  Finally, the 
principle that underlies the access modifiers (modulo the idiosyncrasy of 
`open`) is that of a bounded scope.  But this principle is implicit - each 
keyword is defined on an ad-hoc basis rather than making the underlying 
principle explicit and defining any shorthand we want in terms of that (as 
syntactic sugar for common cases and recommended defaults).

This is why I strongly believe the best approach is to make the underlying 
principle of scopes and capabilities with an `internal` default explicit.  I 
think this principle is easy to teach and easy to understand once it is made 
explicit.  It is a wonderful (but currently rather hidden) aspect of Swift.  If 
we can teach users to understand this principle and to learn the names of 
scopes and capabilities they will not find it difficult and complex.  They will 
find it as easy to learn as a library function: we would have 
`scope(<capbability name>, <scope name>)`**.  The capability would be defaulted 
to basic visibility.  The scope would be defaulted to the current scope.  

Consider scope(inherit, public)`.  It would read like “the scope of inheritance 
is public”.  It tells the reader *exactly* what is happening.  We could 
conceptualize shortened like `open` as something like `accessalias open = 
scope(inherit, public)`.  Tools could even allow you to cmd-Click to the 
definition to see a definition like this.  Users would learn something that is 
no more complicated than a single function call and any time they are confused 
by shorthand they could cmd-Click or look up documentation that explains it 
clearly in terms of this "function call”.  Note: `accessalias` wouldn’t be a 
real thing, just a way to document and explain the shorthand keywords we have 
for “soft defaults” and common conveniences.

This seems to me like a very simple and elegant yet extraordinarily powerful 
system.  I think it’s much better than a small collection of ad-hoc definitions 
of very specific behaviors.

**Anyone who has been reading my thoughts on this might notice that I am using 
`scope` rather than `scoped` in this post.  As I was writing this I realized 
that when we think of access in terms of capability it reads better with 
`scope` than it does with `scoped` (i.e. “inheritance is scoped public” does 
not read as well as “the scope of inheritance is public".

> 
> Thanks,
> Jon

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to