SE-0025: Scoped Access Level, next steps

Outer

···

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

After replying and seeing it in code, it felt so wrong, that I am updating
the proposal now. It should be Inner only.

···

On Mon, Mar 28, 2016 at 8:11 AM Matthew Judge <matthew.judge@gmail.com> wrote:

That is not clear to me in the proposal. The proposal states: "When a
function or a property is defined with `private` access modifier, it is
visible only within that lexical scope." The most immediate lexical scope
for innerVar would be Inner.

I'm not advocating either way, just that it be clear in the proposal.

On Mon, Mar 28, 2016 at 7:48 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com> > wrote:

Outer

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> >> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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@swift.org> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Would it really make sense to allow extensions in other files to access

fileprivate members/funcs?

no, fileprivate is limited to the specific file in which it is used.

···

On Mon, Mar 28, 2016 at 1:13 PM Cheyo Ximenez <cheyo@masters3d.com> wrote:

Let's say that we go with
public, moduleprivate, fileprivate, scopeprivate

Would it really make sense to allow extensions in other files to access
fileprivate members/funcs? The inclusion of the word 'file' in the name
would make it confusing that extensions have the special power to reach
into a fileprivate from another file. This almost begs for another access
like typeprivate (I am not proposing this).

My understating is that scopeprivate came about as a way to deal with
extensions, perhaps the author needs to look into a way to tag
methods/members as not extendable or hidden from extensions only. The
solution would probably be swift specific and it should probably brake out
from the norm of other languages.

On Mar 28, 2016, at 5:46 AM, Ross O'Brien via swift-evolution < > swift-evolution@swift.org> wrote:

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@swift.org> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner, thus innerVar would *not* be visible in Outer, it would only be visible in Inner.

···

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That is not clear to me in the proposal. The proposal states: "When a
function or a property is defined with `private` access modifier, it is
visible only within that lexical scope." The most immediate lexical scope
for innerVar would be Inner.

I'm not advocating either way, just that it be clear in the proposal.

···

On Mon, Mar 28, 2016 at 7:48 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

Outer

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> > wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Let's say that we go with
public, moduleprivate, fileprivate, scopeprivate

Would it really make sense to allow extensions in other files to access fileprivate members/funcs? The inclusion of the word 'file' in the name would make it confusing that extensions have the special power to reach into a fileprivate from another file. This almost begs for another access like typeprivate (I am not proposing this).

My understating is that scopeprivate came about as a way to deal with extensions, perhaps the author needs to look into a way to tag methods/members as not extendable or hidden from extensions only. The solution would probably be swift specific and it should probably brake out from the norm of other languages.

···

On Mar 28, 2016, at 5:46 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org> wrote:

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@swift.org> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That is a deal breaker for me and it is a departure of of the current swift model of localprivate aka private.

I don’t like it. The introduction of a first class scopeprivate is not worth it if that is one of the tradeoffs.

There are other ways to hide implementation now using nested functions.

func outside() -> Int{
    func insidelocalfunc() -> Int {return 2}
    return insidelocalfunc()
}

···

On Mar 28, 2016, at 11:16 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

> Would it really make sense to allow extensions in other files to access fileprivate members/funcs?

no, fileprivate is limited to the specific file in which it is used.

On Mon, Mar 28, 2016 at 1:13 PM Cheyo Ximenez <cheyo@masters3d.com <mailto:cheyo@masters3d.com>> wrote:
Let's say that we go with
public, moduleprivate, fileprivate, scopeprivate

Would it really make sense to allow extensions in other files to access fileprivate members/funcs? The inclusion of the word 'file' in the name would make it confusing that extensions have the special power to reach into a fileprivate from another file. This almost begs for another access like typeprivate (I am not proposing this).

My understating is that scopeprivate came about as a way to deal with extensions, perhaps the author needs to look into a way to tag methods/members as not extendable or hidden from extensions only. The solution would probably be swift specific and it should probably brake out from the norm of other languages.

On Mar 28, 2016, at 5:46 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@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@gmail.com <mailto:matthew.judge@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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Matthew, please take a look at my example with functions (it works today).
In terms of scope, it should be the same with classes. I updated the
proposal to restrict private to the immediate scope, so with the update, it
will be Inner. Please take a look at the proposal. I tried to be very clear
about both the meaning and motivation in the proposal example.

···

On Mon, Mar 28, 2016 at 8:58 AM Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution < > swift-evolution@swift.org> wrote:

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner, thus
innerVar would *not* be visible in Outer, it would only be visible in Inner.

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> > wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I *still* don't understand your reasoning here. If a private member can

be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

The simplest answer is that it's the most private access level, and also
one that doesn't create any confusion. We already discussed several times
here whether inner should have access to outer or the other way around.
With this design, the answer is neither.

A longer answer is that if you move a function into a type and make it a
member function, you change the semantics. It's no longer the same
function. If you move the type inside another type, the semantics is the
same. The only difference is that we get shorter names. Also, if you move a
function to be a member function, that changes the class API. If you move a
class to become a nested class, that does not change the outer class API.
Both classes can be used the same way but with different spelling of the
name of the inner class.

Also, I think that the terminology of access level really comes from OOP.
The problem with the current state of things is that it mixes this
terminology with export levels. This proposal makes "private" mean what it
means in OOP and extends it so that it makes sense with Swift extensions.

If we were talking about "scoped" level access, the immediate scope
addition would be wrong. But if we are talking about "private", it's a
different matter.

···

On Mon, Mar 28, 2016 at 1:38 PM Jordan Rose <jordan_rose@apple.com> wrote:

I *still* don't understand your reasoning here. If a private member can
be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

I don't have a notion of "immediate lexical scope". Nothing else in Swift
is only visible in the "immediate" level of curly-braces.

(This doesn't mean that everything can *successfully* be referenced from
an inner scope; for instance, a local type declared in a function cannot
capture local variables or 'self'. But there's a technical limitation
there, and even *with* that you still find those names via name lookup.)

I am actively against this form of the proposal (regardless of names) and
I'm sorry I didn't notice the intent here the first time around.

Jordan

On Mar 28, 2016, at 6:06, Ilya Belenkiy via swift-evolution < > swift-evolution@swift.org> wrote:

Matthew, please take a look at my example with functions (it works today).
In terms of scope, it should be the same with classes. I updated the
proposal to restrict private to the immediate scope, so with the update, it
will be Inner. Please take a look at the proposal. I tried to be very clear
about both the meaning and motivation in the proposal example.

On Mon, Mar 28, 2016 at 8:58 AM Matthew Johnson <matthew@anandabits.com> > wrote:

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution < >> swift-evolution@swift.org> wrote:

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner,
thus innerVar would *not* be visible in Outer, it would only be visible in
Inner.

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> >> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I still don't understand your reasoning here. If a private member can be used in a member function, and in closures inside that member function, why can't it be used in a member type?

I don't have a notion of "immediate lexical scope". Nothing else in Swift is only visible in the "immediate" level of curly-braces.

(This doesn't mean that everything can successfully be referenced from an inner scope; for instance, a local type declared in a function cannot capture local variables or 'self'. But there's a technical limitation there, and even with that you still find those names via name lookup.)

I am actively against this form of the proposal (regardless of names) and I'm sorry I didn't notice the intent here the first time around.

Jordan

···

On Mar 28, 2016, at 6:06, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

Matthew, please take a look at my example with functions (it works today). In terms of scope, it should be the same with classes. I updated the proposal to restrict private to the immediate scope, so with the update, it will be Inner. Please take a look at the proposal. I tried to be very clear about both the meaning and motivation in the proposal example.

On Mon, Mar 28, 2016 at 8:58 AM Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner, thus innerVar would *not* be visible in Outer, it would only be visible in Inner.

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com <mailto:matthew.judge@gmail.com>> wrote:
On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@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@gmail.com <mailto:matthew.judge@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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I don't buy this argument. Before Swift, there have been plenty of OO languages with extensions and plenty with access control, but no major ones with both except Ruby (discounting Objective-C's @private instance variables). And, ignoring extensions, the behavior of 'private' in all of these languages is to include access from member types:

- C++: yes
- Java: yes
- C#: yes

- Ruby: no, but even the outer class can't invoke private methods on a different instance of itself
- D: yes, but D's "private" is closer to Swift's current "private" than anything else

- Kotlin: yes
- Scala, Python, Go, Rust, Objective-C, Smalltalk: either no access control or no nested types, AFAICT

So "private" in these languages doesn't seem to mean "restricted to this type", and that shouldn't be considered the "obvious" meaning when several of us have considered it decidedly non-obvious.

Best,
Jordan

P.S. "If you move the type inside another type, the semantics is the same." This already isn't true if the new member type is used to satisfy a protocol requirement (which, because of retroactive modeling, counts as "changing the class's API"), but it especially won't be true if/when we start allowing member types inside generic types. In that case, the inner type now has extra generic parameterization that it wouldn't have had before.

P.S. Extensions do make things a little more complicated, but again, there's almost no precedent here, and pretty much everyone agrees that this new scope-private access level shouldn't give access to extensions. That also means there's an option to keep yourself from accidentally accessing scope-private members in a member type: put the member type in an extension.

···

On Mar 28, 2016, at 11:40, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

> I still don't understand your reasoning here. If a private member can be used in a member function, and in closures inside that member function, why can't it be used in a member type?

The simplest answer is that it's the most private access level, and also one that doesn't create any confusion. We already discussed several times here whether inner should have access to outer or the other way around. With this design, the answer is neither.

A longer answer is that if you move a function into a type and make it a member function, you change the semantics. It's no longer the same function. If you move the type inside another type, the semantics is the same. The only difference is that we get shorter names. Also, if you move a function to be a member function, that changes the class API. If you move a class to become a nested class, that does not change the outer class API. Both classes can be used the same way but with different spelling of the name of the inner class.

Also, I think that the terminology of access level really comes from OOP. The problem with the current state of things is that it mixes this terminology with export levels. This proposal makes "private" mean what it means in OOP and extends it so that it makes sense with Swift extensions.

If we were talking about "scoped" level access, the immediate scope addition would be wrong. But if we are talking about "private", it's a different matter.

This is incorrect; the current Swift model for "private" does not privilege anything in other files (or other modules), even extensions. This proposal does not change that, either for the existing file-private level being renamed, or for the new scope-private level being proposed.

Jordan

···

On Mar 28, 2016, at 11:54, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org> wrote:

That is a deal breaker for me and it is a departure of of the current swift model of localprivate aka private.

I don’t like it. The introduction of a first class scopeprivate is not worth it if that is one of the tradeoffs.

There are other ways to hide implementation now using nested functions.

func outside() -> Int{
    func insidelocalfunc() -> Int {return 2}
    return insidelocalfunc()
}

On Mar 28, 2016, at 11:16 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@gmail.com>> wrote:

> Would it really make sense to allow extensions in other files to access fileprivate members/funcs?

no, fileprivate is limited to the specific file in which it is used.

On Mon, Mar 28, 2016 at 1:13 PM Cheyo Ximenez <cheyo@masters3d.com <mailto:cheyo@masters3d.com>> wrote:
Let's say that we go with
public, moduleprivate, fileprivate, scopeprivate

Would it really make sense to allow extensions in other files to access fileprivate members/funcs? The inclusion of the word 'file' in the name would make it confusing that extensions have the special power to reach into a fileprivate from another file. This almost begs for another access like typeprivate (I am not proposing this).

My understating is that scopeprivate came about as a way to deal with extensions, perhaps the author needs to look into a way to tag methods/members as not extendable or hidden from extensions only. The solution would probably be swift specific and it should probably brake out from the norm of other languages.

On Mar 28, 2016, at 5:46 AM, Ross O'Brien via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@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@gmail.com <mailto:matthew.judge@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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

If I may be so bold, as a programmer with over 25 years of experience, in multiple languages…

Although I can see the reasoning behind "redefining" visibility scope for Swift, I find myself both agreeing and disagreeing with various aspects.

Apart from Delphi, I've never come across a use of private other than for the scope of the immediate class only. Delphi does a similar thing to Swift, in that it defines "private" as meaning the scope of the declaring code file until Delphi 7, when someone decided it was a good idea (possibly due to user requests) to add "strict private" to indicate a "true" private member, visible only to the declaring class.

Likewise, at the same time, "strict protected", was added to convey visibility only to inherited classes, in addition to "protected", which means roughly the same as "private". Thus giving Delphi, in order of visibility, "strict private", "strict protected", "private", "protected" and "public". There are even ungodly hacks that allow you to access the private fields of a class in another unit!!!

However, in Swift, we can declare a lot more types as "private", but "protected" really doesn't seem to make sense outside of classes, as there is no inheritance for other types like structs and enums.

But, in Swift, we now have the concept of extensions on all types, making inheritance less necessary and prompting us towards protocol-based programming, where behaviours can be added to any number of types without having to limit that type's inheritance from a base type. Now we can define behaviours that can apply to classes, structs, enums and, even, basic types such as Int and String.

Take the example of the Visitor Pattern : With strictly typed and statically compiled languages, this classically ends up with a system of double dispatch between a hierarchy of classes and a hierarchy of visitors.

Objective-C's class categories permit the extension of a class's behaviour without the Visitor Pattern but, with danger of dynamic dispatch that a "visitation" method may be called when it does not exist in the category. Another problem being that categories can only access "public" members of the main class because "public" is the only visibility Objective-C understands outside of iVars.

Swift's extensions permit the extension of most types (not just classes) so that they can implement one or more protocols, ensuring that the protocol(s) is/are fully implemented by raising a compiler error if not satisfied.

So, if we are going to bring in visibility specifiers to Swift, with all of its wonderful, type-safe, statically compiled code, we have to carefully consider, not just the names of the planned scopes but what impact any restrictions may have on the use of protocol-oriented programming and the various extensions on types that it will engender.

C++ uses the concept of marking certain methods and classes as "friend", so that nominated classes have privileged access to otherwise private members of a class; maybe this is a worthwhile concept for determining what parts of a type can be accessed by an extension?

I am not suggesting "friend" as a name but the need for being able to restrict or allow access to certain members of a type when extending it?

In the light of the preceding paragraphs, I would, respectfully, suggest that "protected" should be allowed for exclusive use in the case of classes that really have to derive from each other, but for no other reason. Likewise, "private" should mean what it has meant and still means in most other languages, members of classes only, since, like "protected", that is its true nature.

What Swift presently calls "internal" seems to equate more to the C# concept of "internal" and, in my mind, needs no further discussion or change.

Just as I was never happy with the Delphi concept of private and protected members being accessible, not just in the class or its derived types, but also from any code in the same code unit, I feel uneasy about the present definition of the private scope in Swift.

I have seen some horrendous abuses of that privileged access, with the gradual growth of single code units to truly gargantuan proportions, just because someone felt that certain classes needed to violate all the rules of common sense and be able to access each others' private parts (if you'll pardon the vernacular).

If several types really have to be defined in the same unit, then their relationship to each other needs defining far more strictly than just to say that they have total free reign to interfere where they want.

Personally, I would like to see the end of the file based scope and, instead, see more clearly defined "privileged" access between types, even if they are in the same code unit.

Let the naysayers (or even the forsayers) commence :-)

Joanna

···

--
Joanna Carter
Carter Consulting

If the core team is against that reasoning, maybe the proposal can be
"accepted with modification" that discards the "immediate scope" addition
and makes it "scoped". Since this was discussed here, and I feel strongly
that it's the clearest and most natural answer to many questions raised in
the discussion, I wanted to include it.

···

On Mon, Mar 28, 2016 at 2:40 PM Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

> I *still* don't understand your reasoning here. If a private member can
be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

The simplest answer is that it's the most private access level, and also
one that doesn't create any confusion. We already discussed several times
here whether inner should have access to outer or the other way around.
With this design, the answer is neither.

A longer answer is that if you move a function into a type and make it a
member function, you change the semantics. It's no longer the same
function. If you move the type inside another type, the semantics is the
same. The only difference is that we get shorter names. Also, if you move a
function to be a member function, that changes the class API. If you move a
class to become a nested class, that does not change the outer class API.
Both classes can be used the same way but with different spelling of the
name of the inner class.

Also, I think that the terminology of access level really comes from OOP.
The problem with the current state of things is that it mixes this
terminology with export levels. This proposal makes "private" mean what it
means in OOP and extends it so that it makes sense with Swift extensions.

If we were talking about "scoped" level access, the immediate scope
addition would be wrong. But if we are talking about "private", it's a
different matter.

On Mon, Mar 28, 2016 at 1:38 PM Jordan Rose <jordan_rose@apple.com> wrote:

I *still* don't understand your reasoning here. If a private member can
be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

I don't have a notion of "immediate lexical scope". Nothing else in Swift
is only visible in the "immediate" level of curly-braces.

(This doesn't mean that everything can *successfully* be referenced from
an inner scope; for instance, a local type declared in a function cannot
capture local variables or 'self'. But there's a technical limitation
there, and even *with* that you still find those names via name lookup.)

I am actively against this form of the proposal (regardless of names) and
I'm sorry I didn't notice the intent here the first time around.

Jordan

On Mar 28, 2016, at 6:06, Ilya Belenkiy via swift-evolution < >> swift-evolution@swift.org> wrote:

Matthew, please take a look at my example with functions (it works
today). In terms of scope, it should be the same with classes. I updated
the proposal to restrict private to the immediate scope, so with the
update, it will be Inner. Please take a look at the proposal. I tried to be
very clear about both the meaning and motivation in the proposal example.

On Mon, Mar 28, 2016 at 8:58 AM Matthew Johnson <matthew@anandabits.com> >> wrote:

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution < >>> swift-evolution@swift.org> wrote:

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner,
thus innerVar would *not* be visible in Outer, it would only be visible in
Inner.

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com> >>> wrote:

On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@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@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@swift.org> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution < >>>>>> swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Jordan, I agree with you. IMO this is a change to the proposal that was not requested by the core team. The meaning of private was accepted was clearly the traditional meaning of lexical scope, which cleanly follows the nesting of scopes used by the other access control modifiers.

The modified proposal should only change the declaration modifiers used, not any semantics. If anyone, including Ilya, wants to introduce more “exotic” semantics this should be done in a new proposal that starts the process from the beginning.

···

On Mar 28, 2016, at 12:38 PM, Jordan Rose <jordan_rose@apple.com> wrote:

I still don't understand your reasoning here. If a private member can be used in a member function, and in closures inside that member function, why can't it be used in a member type?

I don't have a notion of "immediate lexical scope". Nothing else in Swift is only visible in the "immediate" level of curly-braces.

(This doesn't mean that everything can successfully be referenced from an inner scope; for instance, a local type declared in a function cannot capture local variables or 'self'. But there's a technical limitation there, and even with that you still find those names via name lookup.)

I am actively against this form of the proposal (regardless of names) and I'm sorry I didn't notice the intent here the first time around.

Jordan

On Mar 28, 2016, at 6:06, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Matthew, please take a look at my example with functions (it works today). In terms of scope, it should be the same with classes. I updated the proposal to restrict private to the immediate scope, so with the update, it will be Inner. Please take a look at the proposal. I tried to be very clear about both the meaning and motivation in the proposal example.

On Mon, Mar 28, 2016 at 8:58 AM Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Mar 28, 2016, at 6:48 AM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Outer

Why Outer? It looks to me like the enclosing lexical scope is Inner, thus innerVar would *not* be visible in Outer, it would only be visible in Inner.

On Mon, Mar 28, 2016 at 7:30 AM Matthew Judge <matthew.judge@gmail.com <mailto:matthew.judge@gmail.com>> wrote:
On Mon, Mar 28, 2016 at 6:41 AM, Ilya Belenkiy <ilya.belenkiy@gmail.com <mailto:ilya.belenkiy@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@gmail.com <mailto:matthew.judge@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@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 27 Mar 2016, at 19:34, Jose Cheyo Jimenez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

The only example that comes to mind is Ruby, where I can add new methods to an existing class, and those new methods indeed have access to existing ‘private’ methods:

class A
  private def foo()
    puts “foo called”
  end
end

A.new.foo() # error

class A
  def bar() # add new bar method
    foo()
  end
end

A.new.bar() # prints “foo called”

···

On Mar 28, 2016, at 2:30 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

P.S. Extensions do make things a little more complicated, but again, there's almost no precedent here, and pretty much everyone agrees that this new scope-private access level shouldn't give access to extensions. That also means there's an option to keep yourself from accidentally accessing scope-private members in a member type: put the member type in an extension.

Ok, I guess I never used nested types much in C++. If this is standard, I
don't want to change it. I'll revert back to the pure "scoped" meaning.
Thank you, this was very useful.

···

On Mon, Mar 28, 2016 at 4:30 PM Jordan Rose <jordan_rose@apple.com> wrote:

On Mar 28, 2016, at 11:40, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

> I *still* don't understand your reasoning here. If a private member can
be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

The simplest answer is that it's the most private access level, and also
one that doesn't create any confusion. We already discussed several times
here whether inner should have access to outer or the other way around.
With this design, the answer is neither.

A longer answer is that if you move a function into a type and make it a
member function, you change the semantics. It's no longer the same
function. If you move the type inside another type, the semantics is the
same. The only difference is that we get shorter names. Also, if you move a
function to be a member function, that changes the class API. If you move a
class to become a nested class, that does not change the outer class API.
Both classes can be used the same way but with different spelling of the
name of the inner class.

Also, I think that the terminology of access level really comes from OOP.
The problem with the current state of things is that it mixes this
terminology with export levels. This proposal makes "private" mean what it
means in OOP and extends it so that it makes sense with Swift extensions.

If we were talking about "scoped" level access, the immediate scope
addition would be wrong. But if we are talking about "private", it's a
different matter.

I don't buy this argument. Before Swift, there have been plenty of OO
languages with extensions and plenty with access control, but no major ones
with both except Ruby (discounting Objective-C's @private instance
variables). And, ignoring extensions, the behavior of 'private' in all of
these languages is to include access from member types:

- C++: yes
- Java: yes
- C#: yes

- Ruby: no, but even the outer class can't invoke private methods on a
different instance of itself
- D: yes, but D's "private" is closer to Swift's current "private" than
anything else

- Kotlin: yes
- Scala, Python, Go, Rust, Objective-C, Smalltalk: either no access
control or no nested types, AFAICT

So "private" in these languages doesn't seem to mean "restricted to this
type", and that shouldn't be considered the "obvious" meaning when several
of us have considered it decidedly non-obvious.

Best,
Jordan

P.S. "If you move the type inside another type, the semantics is the
same." This already isn't true if the new member type is used to satisfy a
protocol requirement (which, because of retroactive modeling, counts as
"changing the class's API"), but it especially won't be true if/when we
start allowing member types inside generic types. In that case, the inner
type now has extra generic parameterization that it wouldn't have had
before.

P.S. Extensions do make things a little more complicated, but again,
there's almost no precedent here, and pretty much everyone agrees that this
new scope-private access level shouldn't give access to extensions. That
also means there's an option to keep yourself from accidentally accessing
scope-private members in a member type: put the member type in an extension.

Some responses rolled into a single email:

I'm going to say that I remain unhappy with these new names. I don't believe that these won't get used, and I don't want them to feel awkward, discouraged, or penalized when they do. The standard library, for example, has in its style guide that all access control should be explicit, which is a reasonable style to enforce.

I enforce that style in my own code, so I'll definitely be using moduleprivate. The point was that, if you don't like moduleprivate, you can establish a code style that omits it. But I personally like it very much, it's an ideal mix of standing out (by virtue of being long), but not standing out too much.

I also have a small concern that they won't be easy to talk about: "this method is private" "wait, file-private or module-private?" "neither, just private-private".

Nope, you'll just always say file-private and module-private when you mean that. Private continues to mean private. No need to clarify when speaking.

I've never come across a use of private other than for the scope of the immediate class only.

Yes. Private should be the scoped access level, that's the least surprising definition.

Delphi does a similar thing to Swift, in that it defines "private" as meaning the scope of the declaring code file

FWIW, Delphi and Ada had a strong tradition of module/unit-based encapsulation (where the module/unit refers to a single file or a header/body pair of files), with each module having public and private parts.

Swift doesn't go all the way here, but it does recognize that it's a useful pattern. I personally like it, and use file-private access regularly to group related entities into a single submodule. (There sure are other ways to define submodules, but this is the most lightweight one, and also the one we already have.)

So “fileprivate” should definitely stay, but yes, it's not nearly as common as “private”.

I would, respectfully, suggest that "protected" should be allowed for exclusive use in the case of classes that really have to derive from each other

I would personally love this, but it's outside the scope of the current proposal.

What Swift presently calls "internal" seems to equate more to the C# concept of "internal" and, in my mind, needs no further discussion or change.

I believe “moduleprivate” is a lot more clear than “internal”. “internal” have always bugged me as a seemingly random word.

Let's say that we go with public, moduleprivate, fileprivate, scopeprivate

God no. “Private” is the most common case, and shouldn't stand out that much. Scoped private will be consistent with every other language out there, so doesn't need clarification.

I have seen some horrendous abuses of that privileged access, with the gradual growth of single code units to truly gargantuan proportions, just because someone felt that certain classes needed to violate all the rules of common sense and be able to access each others' private parts (if you'll pardon the vernacular).

Respectfully, this is not a valid argument. I've seen horrific abuses in lots of different languages out there. Bad developers will always write bad code, and the intricacies of access level definitions won't help.

If several types really have to be defined in the same unit, then their relationship to each other needs defining far more strictly than just to say that they have total free reign to interfere where they want.

Yes, this is why certain members should be marked file-private. We don't need explicit friends. If a file grows beyond the size where the purpose is clear, the code needs to be refactored into multiple files.

public, internal, private, secret.

No. Private needs to mean what everyone expects it to mean, and it should also be the default reasonable (i.e. most restricting) choice.

+1 to paren syntax for readability, private(module) being the default if nothing declared, private with no parenthesized access keyword can default to either file or scope.

There's nothing readable about private(module). You don't want those parens to grab attention from the code. A longish word is quite enough.

I still think that "local" expresses the concept exactly, as it restricts visibility to the local scope, doesn't it?

No, to me it's only clear if you stop and think about it. But when coding, it invokes all the wrong associations.

afaics this is the third time someone mentions that "file-private" is uncommon — so I think it's time someone dissents:

I'll do the same. There's many instances in my code where I rely on the file-private behavior of Swift 2's private. Mostly this happens when I have a pair of coupled classes that are meant to be used together and that need to access internal details of each other. Most declarations can be scope-private without problem, but it's not that uncommon for me to take advantage of file-private.

+1

It *is* fairly common, but:

1) it is *way less* common than just plain private

2) in those cases where I need file-private, I really want to document *which* members are accessed from outside, so the distinction between private and file-private is very useful there

I cannot come up with a single use-case in my code for fileprivate and would love
some real world examples where you'd want visibility in a single file but not across
an entire module.

Here's a quick use case: a private helper class that you don't want to expose to the outside. Maybe it's only used to implement a verbose protocol. It's really a part of the bigger public class, so wants to access some of its members without much ado.

Another use case: a bunch of public structs/classes that can be initialized from JSON, but there's only a single publicly-visible ‘parse’ method that invokes a bunch of private initializers (and maybe mutation methods) on those structs.

There are tons of cases where you have a compact bunch of classes and you want them to hide the implementation details of one specific feature that involves interaction between them.

Haven't you even declared a bunch of Objective-C classes in a single file so that they all have access to the the private extensions of one another? I did it fairly often, and Swift's file-private is a natural extension of that.

Abandon the words 'public' and 'private'. [...] I really want Swift to use terms with clear meaning

“Private” has a very clear meaning (not accessible from outside); its current meaning was simply a wrong choice, based on a different look at what “outside” means.

Similarly, “public” is 100% clear; we talk about “public API” all the time.

We also talk about module-private, subsystem-private, framework-private and file-private stuff, so calling them such seems a no-brainer choice. Do you ever say “file-internal” yourself?

public (unchanged)
external (module access)
internal (file access)
private (scoped access)

This seems logical and something I could live with, but how is it better than moduleprivate and fileprivate? Also, internal has contradictory prior art in C# and Swift 2 (not that it stops us).

And I see the length of moduleprivate and fileprivate as a feature, and external/internal lacks it.

protected // Java got it wrong. :) This is "protected" against extensions. '

Please leave protected alone, I still hope we can get it into the language in some shape or form, not necessarily bound to subclasses.

If I may be so bold, as a programmer with over 25 years of experience, in multiple languages…

15 years here, just so that you don't disregard this as a newbie's talk. (I fully expect to be wrong on occasion, though, so I don't consider this to be a part of the argument.)

A.

Scala has a sophisticated and interesting access level that might well be
good fit to Swift (since the two languages are very similar), e.g
Swiftizing some Scala:

class society {

class professional {

class Executive {

private(society) var friends = ...

private(professional) var workDetails = ...

private var secrets = ...

func executive() {

print(friends) // OK inside society

print(workDetails) // OK inside professional

print(secrets) // OK inside Executive

}

}

func professional() {

           print(friends) // OK inside society

           print(workDetails) // OK inside professional

           print(secrets) // ERROR outside Executive

}

}

func society() {

           print(friends) // OK inside society

           print(workDetails) // ERROR outside professional

           print(secrets) // ERROR outside Executive

}

}

var exec = society.professional.Executive()

print(exec.friends) // ERROR outside society
print(exec.workDetails) // ERROR outside professional
print(exec.secrets) // ERROR outside Executive

In Scala access is:

   1. public, private, or private(S); plus protected for abstract classes
   and private(self) for generic classes with generic variance - neither
   relevant to this discussion
   2. public behaves as expected
   3. The default is public, therefore in the example above society,
   professional, Executive, and the functions are all public
   4. private is scoped so that is only visible within its enclosing scope,
   hence secrets is only visible inside Executive
   5. private(S) extends the visibility to the named enclosing scope S,
   hence workDetails is visible inside professional's scope because it is
   declared private(professional)

If Scala style access modifiers were adopted for Swift then a private(file)
modifier would also be necessary to give the current private functionality.

Note Scala has modules, called packages, and in the Scala example I copied
and converted to Swift above the society and professional classes were
packages and hence there lower-case spelling. Class was the nearest
substitute in Swift for a scala package. The original Scala is from:

  -- Howard.

···

On 29 March 2016 at 07:30, Jordan Rose via swift-evolution < swift-evolution@swift.org> wrote:

On Mar 28, 2016, at 11:40, Ilya Belenkiy <ilya.belenkiy@gmail.com> wrote:

> I *still* don't understand your reasoning here. If a private member can
be used in a member function, and in closures inside that member function,
why can't it be used in a member type?

The simplest answer is that it's the most private access level, and also
one that doesn't create any confusion. We already discussed several times
here whether inner should have access to outer or the other way around.
With this design, the answer is neither.

A longer answer is that if you move a function into a type and make it a
member function, you change the semantics. It's no longer the same
function. If you move the type inside another type, the semantics is the
same. The only difference is that we get shorter names. Also, if you move a
function to be a member function, that changes the class API. If you move a
class to become a nested class, that does not change the outer class API.
Both classes can be used the same way but with different spelling of the
name of the inner class.

Also, I think that the terminology of access level really comes from OOP.
The problem with the current state of things is that it mixes this
terminology with export levels. This proposal makes "private" mean what it
means in OOP and extends it so that it makes sense with Swift extensions.

If we were talking about "scoped" level access, the immediate scope
addition would be wrong. But if we are talking about "private", it's a
different matter.

I don't buy this argument. Before Swift, there have been plenty of OO
languages with extensions and plenty with access control, but no major ones
with both except Ruby (discounting Objective-C's @private instance
variables). And, ignoring extensions, the behavior of 'private' in all of
these languages is to include access from member types:

- C++: yes
- Java: yes
- C#: yes

- Ruby: no, but even the outer class can't invoke private methods on a
different instance of itself
- D: yes, but D's "private" is closer to Swift's current "private" than
anything else

- Kotlin: yes
- Scala, Python, Go, Rust, Objective-C, Smalltalk: either no access
control or no nested types, AFAICT

So "private" in these languages doesn't seem to mean "restricted to this
type", and that shouldn't be considered the "obvious" meaning when several
of us have considered it decidedly non-obvious.

Best,
Jordan

P.S. "If you move the type inside another type, the semantics is the
same." This already isn't true if the new member type is used to satisfy a
protocol requirement (which, because of retroactive modeling, counts as
"changing the class's API"), but it especially won't be true if/when we
start allowing member types inside generic types. In that case, the inner
type now has extra generic parameterization that it wouldn't have had
before.

P.S. Extensions do make things a little more complicated, but again,
there's almost no precedent here, and pretty much everyone agrees that this
new scope-private access level shouldn't give access to extensions. That
also means there's an option to keep yourself from accidentally accessing
scope-private members in a member type: put the member type in an extension.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution