[swift-evolution] SE-0025: Scoped Access Level, next steps

Ross O'Brien narrativium+swift at gmail.com
Mon Mar 28 07:46:45 CDT 2016


Ilya said:
> "public", "protected", and "private" have a very well defined meaning in
OOP. We shouldn't redefine them without a good reason.

I agree. Swift has a scope-based visibility system, not a type-based
visibility system, but because Swift redefines the terms 'public' and
'private', programmers keep getting confused about how they're used in
Swift.

Over the last few posts, since Chris Lattner proposed switching to:
'public, internal, X, private', we've had several new scales proposed. (In
every scale in this post, there are four terms in order of decreasing
visibility, with the second term being the default.)

public, external, internal, private.
public, internal, private, secret.
external, internal, public, private.
public, internal, private, secret.
public, internal, private, local.

At this point, respectfully, I think we can dismiss the idea that labelling
any given level as 'public' or 'private' is right or obvious. Swift is
built around clarity at the point of use. 'private' is not as clear as you
maintain it is.

> Swift allows extensions, so "private" in its standard form doesn't work
well -- you could just define an extension and get access to anything. The
scope based private seems to be the most natural extension (pun intended
:–)).

We're redefining terms from a type-based visibility scale to a scope-based
visibility scale. I'm not disagreeing that an extension would allow access
to type-visible symbols and that this might not be the programmer's
intention, but that 'private' has a clear meaning in OOP and repurposing
'private' is not resolving any confusion.

> I'd like to keep "private" to be completely private and not allow class
injection to gain access, but this is an edge case that could be argued
either way. I can definitely live with a pure scoped access  for
consistency and don't want to argue the edge case in a never ending
discussion.

As far as I know, it's not an edge case in Swift, it's a non-case. Swift
doesn't have type-based visibility. Using Swift's system, I do understand
that you want 'private' to refer to the least-visible level in the
hierarchy.

However, as has already been pointed out, the scope-visible level is not
the least-visible conceivable. There's already discussion over whether the
properties of inner types should be visible to their outer types. If that
ever made its way to a proposal, would that level become 'private'? I think
we can agree that another bikeshedding conversation like this would rather
be avoided.

There's also the possibility of a 'submodule' level. Chris Lattner
suggested that the 'private(foo.bar)' syntax might be best for this, but I
don't know what that means - whether 'submodule' would be within the Swift
hierarchy or not - but it's a possibility for the future.

I'm repeating myself, but: inclusion of the terms 'module', 'file', and
'scope' in our symbols is winning out in clarity. None of those terms has
changed meaning in the entire discussion. The only question is exactly how
they should be welded to the term 'private'. There've been three
suggestions for doing this so far and they're all awkward, either because
they have parentheses or they're conjoined, but they're unambiguous in
meaning and no-one's suggested any single-word ideas with the same clarity.

public, private(module), private(file) and private(scope).
public, moduleprivate, fileprivate, scopeprivate.
public, privatetomodule, privatetofile, privatetoscope.

I'm tempted to go one further, but if you want to ignore that one further,
skip the next two paragraphs:

Abandon the words 'public' and 'private'. Let's just accept that, together
with 'protected', these are well-defined terms of type-based visibility in
OOP which are orthogonal to Swift's hierarchy, and that redefining them
leads to confusion. Embrace 'external' and 'internal' in their places:

external, internal(module), internal(file), internal(scope).
external, moduleinternal, fileinternal, scopeinternal.
external, internaltomodule, internaltofile, internaltoscope.

If you ignored that, welcome back.

I hope I've not been too antagonistic about this. I really want Swift to
use terms with clear meaning, and if that breaks code, I want a clean break
that can be easily healed / migrated.

Every suggestion for relabelling this hierarchy, bar 'public, internal,
private, local/scope', breaks code.

Adding the scope-visible level allows for greater control, but I don't
believe module-visible and file-visible levels would be uncommon with its
inclusion, so the terms for all three - all four, really - should be
balanced in their 'ugliness'.

What the proposal as it stands does need to make clear is what would change
and what would be left behind.

If 'internal' is renamed to 'moduleprivate', explicit uses of 'internal'
need to be replaced.

If there are constants, 'global' functions, operators, or anything that can
be defined outside of a scope, their least visible level is fileprivate.
They can never be 'scope-private'.

If 'private' is redefined, it is no nearer to its meaning in other
languages than it is now.


On Mon, Mar 28, 2016 at 12:30 PM, Matthew Judge via swift-evolution <
swift-evolution at swift.org> wrote:

>
>
> On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy at gmail.com>
> wrote:
>
>> lexical scope is the other way around: "inner" can see "outer". For
>> example:
>>
>> func f() {
>>   let outer = 0
>>  // f cannot use inner
>>    func g() {
>>        let inner = 1
>>        // g can use outer
>>    }
>> }
>>
>>
> Maybe I'm off in my terminology, but I think my code example matches what
> you are saying here (outer is visible to g() but inner is not visible to f()
>
>
>> It would work the same way for the access level. That said, I'd rather
>> not include this in the proposal.
>>
>
> So as the proposal stands now, what is the scope that innerVar is visible
> to in the following code: Inner or Outer?
>
> class Outer {
>     class Inner {
>         private var innerVar: Int
>     }
> }
>
>
>> The only change that the core team requested was the name changes. I
>> personally would prefer a completely private version where you cannot
>> inject a class into a scope to get access to the scope internals, but it's
>> an edge case that could be argued either way, and I don't want to start
>> another lengthy discussion. We already had quite a few.
>>
>> On Sun, Mar 27, 2016 at 11:17 PM Matthew Judge <matthew.judge at gmail.com>
>> wrote:
>>
>>> I know it was suggested that it be the subject of a different thread,
>>> but it might be good to clarify how the new private is going to work (or at
>>> least what is currently envisioned).
>>>
>>> My understanding is that the new private would be:
>>> - visible only to the immediately enclosing scope
>>> - including the scope of a inner nested scope
>>> - not including the scope of an outer nested scope
>>> - not visible to an extension
>>>
>>> Said in code (all in the same file):
>>> ----------
>>> class Outer { // Outer visible to module
>>>     private var a: Int // visible to Outer, Inner1, & Inner2
>>>
>>>     class Inner1 { // Inner1 visible to module
>>>         private var b: Int // visible to Inner1 only
>>>     }
>>>     private class Inner2 { // visible to Outer & Inner(s)
>>>         var c: Int // visible to Outer & Inner(s)
>>>     }
>>> }
>>>
>>> extension Outer { // visible to module
>>>     // 'a', 'b', and 'Inner2' NOT visible
>>> }
>>> ----------
>>> If this is the intended meaning of private, then fileprivate seems to be
>>> the same as private (private to the enclosing scope... which happens to be
>>> the file).
>>>
>>> Something declared "private" at the top level of a file is fileprivate.
>>> There would still need to be a way to reference scopes other than the
>>> immediate one (especially since there is no way to say "private" and mean
>>> moduleprivate), though I think it would strengthen the argument for
>>> something along the lines of "private(file)", since it would even further
>>> reduce the cases where you are spelling something more than just "private"
>>>
>>>
>>> On Mar 27, 2016, at 17:31, Haravikk via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>
>>> On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> Public
>>> External (default)
>>> Internal
>>> Private
>>>
>>>
>>> I still feel like these are still too vague; I’m not sure I like the use
>>> of external, as public to me is external since it exports outside of the
>>> module, whereas what you’re proposing is in fact just limited to the module
>>> itself. I dislike the current internal keyword too, but at least it reads
>>> as “internal to this module", this is why the more specific terms are
>>> better like:
>>>
>>> public as-is, item is public/exported outside of module
>>> private(module) or private current internal, item is private to this
>>> module, would be the default
>>> private(file) current private, item is private to this file
>>> private(scope) new visibility type, item is private to the current scope
>>>
>>> Assuming I’m understanding the restriction properly this time =)
>>>
>>> It’s also the easiest method if we do add another visibility later for
>>> sub-classes such as private(type), as it doesn’t even require a new keyword.
>>>
>>> _______________________________________________
>>>
>>>
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160328/8dd830f5/attachment.html>


More information about the swift-evolution mailing list