[Discussion] A Problem With SE-0025?


(Jon Hull) #1

My understanding of the proposal was that the unannotated properties/methods inside of a scope have the same *visibility* as their surrounding scope, or internal, whichever is less.

That is slightly different than having the same access level. Thus:

private struct Outer {
  var inner:Int
}

is different than:

private struct Outer {
  private var inner:Int
}

In the first, inner is accessible precisely everywhere where Outer is accessible. In the second, inner is only accessible within Outer itself. It is important that we have the first behavior for unannotated inner, because there is no other way to spell it.

That is my understanding of the intent of SE-0025, even if the exact wording is confusing.

Thanks,
Jon

P.S. I would personally like to see unannotated properties/methods inside of a scope have the same visibility as their surrounding scope. Full stop. End of sentence. (It seems to me like the special handling of internal is what is causing the confusion here). That is what I would expect the behavior to be if I didn’t know. That isn’t what was written in the proposal though...

···

While implementing SE-0025 (fileprivate), I noticed an interesting bug in the proposal. Under the implementation outlined there, any top-level structure, class, or enum declared private cannot possibly be instantiated and so cannot be used in any way. Because of this, private top-level declarations are more often than not blown away entirely by the compiler for being unused. It seems strange to me to allow a key language feature to act solely as a hint to the optimizer to reduce the size of your binary. Perhaps the restrictions around private needs to be relaxed or the line between fileprivate and private needs to be investigated again by the community before inclusion in the language.

Thoughts?

~Robert Widmann


(Robert Widmann) #2

But the proposal does not specify that and that is not how swift's access control mechanisms currently work, unfortunately. A private aggregate must have private members, and those members are subject to private access whether annotated or not.

On top of that, you break containment this way. A private member is not supposed to be visible outside of its current declaration. An aggregate full of private members similarly. You can see the aggregate, but you cannot see its members. If we relax this, then private is no different from fileprivate and we should just stick to our current tri-valued access control system.

~Robert Widmann

2016/06/15 23:04、Jonathan Hull via swift-evolution <swift-evolution@swift.org> のメッセージ:

···

My understanding of the proposal was that the unannotated properties/methods inside of a scope have the same *visibility* as their surrounding scope, or internal, whichever is less.

That is slightly different than having the same access level. Thus:

private struct Outer {
  var inner:Int
}

is different than:

private struct Outer {
  private var inner:Int
}

In the first, inner is accessible precisely everywhere where Outer is accessible. In the second, inner is only accessible within Outer itself. It is important that we have the first behavior for unannotated inner, because there is no other way to spell it.

That is my understanding of the intent of SE-0025, even if the exact wording is confusing.

Thanks,
Jon

P.S. I would personally like to see unannotated properties/methods inside of a scope have the same visibility as their surrounding scope. Full stop. End of sentence. (It seems to me like the special handling of internal is what is causing the confusion here). That is what I would expect the behavior to be if I didn’t know. That isn’t what was written in the proposal though...

While implementing SE-0025 (fileprivate), I noticed an interesting bug in the proposal. Under the implementation outlined there, any top-level structure, class, or enum declared private cannot possibly be instantiated and so cannot be used in any way. Because of this, private top-level declarations are more often than not blown away entirely by the compiler for being unused. It seems strange to me to allow a key language feature to act solely as a hint to the optimizer to reduce the size of your binary. Perhaps the restrictions around private needs to be relaxed or the line between fileprivate and private needs to be investigated again by the community before inclusion in the language.

Thoughts?

~Robert Widmann

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


(Jon Hull) #3

They happen to be the same at the top level, but they are very different when dealing with nested types…

A private member is visible inside it’s containing scope. For the top-level, that is the file. For a nested type, that is the outer type.

You may, for instance have an outer type which is marked Internal or public, but an inner type which is marked fileprivate so that extensions in the file can use the inner type. That is different than marking the inner type private, which would only allow access inside the outer type, but not in extensions.

Again, I want to point out that the behavior I described in my earlier message is the only plausible/usable behavior because we have no other way to specify that a member should have the same visibility as it’s enclosing scope… which is a common and important use-case. Doing it your way, as you point out in your original message, leads to the problem of having no way to instantiate types marked private.

This was all thoroughly discussed during the proposal process, with lots of people talking about the fact that private & fileprivate are the same at the top level… and the response was that, yes, this is by design. In most cases you can continue to just use the shorter private, and you only need to bring in fileprivate for nested types. Fileprivate is one of those things that you REALLY need when you need it though, which is why it was included.

Thanks,
Jon

···

On Jun 16, 2016, at 12:06 AM, Robert Widmann <devteam.codafi@gmail.com> wrote:

But the proposal does not specify that and that is not how swift's access control mechanisms currently work, unfortunately. A private aggregate must have private members, and those members are subject to private access whether annotated or not.

On top of that, you break containment this way. A private member is not supposed to be visible outside of its current declaration. An aggregate full of private members similarly. You can see the aggregate, but you cannot see its members. If we relax this, then private is no different from fileprivate and we should just stick to our current tri-valued access control system.

~Robert Widmann

2016/06/15 23:04、Jonathan Hull via swift-evolution <swift-evolution@swift.org> のメッセージ:

My understanding of the proposal was that the unannotated properties/methods inside of a scope have the same *visibility* as their surrounding scope, or internal, whichever is less.

That is slightly different than having the same access level. Thus:

private struct Outer {
  var inner:Int
}

is different than:

private struct Outer {
  private var inner:Int
}

In the first, inner is accessible precisely everywhere where Outer is accessible. In the second, inner is only accessible within Outer itself. It is important that we have the first behavior for unannotated inner, because there is no other way to spell it.

That is my understanding of the intent of SE-0025, even if the exact wording is confusing.

Thanks,
Jon

P.S. I would personally like to see unannotated properties/methods inside of a scope have the same visibility as their surrounding scope. Full stop. End of sentence. (It seems to me like the special handling of internal is what is causing the confusion here). That is what I would expect the behavior to be if I didn’t know. That isn’t what was written in the proposal though...

While implementing SE-0025 (fileprivate), I noticed an interesting bug in the proposal. Under the implementation outlined there, any top-level structure, class, or enum declared private cannot possibly be instantiated and so cannot be used in any way. Because of this, private top-level declarations are more often than not blown away entirely by the compiler for being unused. It seems strange to me to allow a key language feature to act solely as a hint to the optimizer to reduce the size of your binary. Perhaps the restrictions around private needs to be relaxed or the line between fileprivate and private needs to be investigated again by the community before inclusion in the language.

Thoughts?

~Robert Widmann

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


(Robert Widmann) #4

~Robert Widmann

2016/06/16 0:29、Jonathan Hull <jhull@gbis.com> のメッセージ:

They happen to be the same at the top level, but they are very different when dealing with nested types…

A private member is visible inside it’s containing scope. For the top-level, that is the file. For a nested type, that is the outer type.

A wonderful idea, but not in the proposal. In fact, the singular example given therein runs directly counter to this idea by explicitly showing the scoping behavior of a private member.

You may, for instance have an outer type which is marked Internal or public, but an inner type which is marked fileprivate so that extensions in the file can use the inner type. That is different than marking the inner type private, which would only allow access inside the outer type, but not in extensions.

That is defined behavior. The inner private type's members are, however, still private and cannot escalate their access beyond that.

Again, I want to point out that the behavior I described in my earlier message is the only plausible/usable behavior because we have no other way to specify that a member should have the same visibility as it’s enclosing scope… which is a common and important use-case. Doing it your way, as you point out in your original message, leads to the problem of having no way to instantiate types marked private.

Then we should amend the proposal posthaste!

This was all thoroughly discussed during the proposal process, with lots of people talking about the fact that private & fileprivate are the same at the top level… and the response was that, yes, this is by design. In most cases you can continue to just use the shorter private, and you only need to bring in fileprivate for nested types. Fileprivate is one of those things that you REALLY need when you need it though, which is why it was included.

Good to know I'm not the only one with reservations.

···

Thanks,
Jon

On Jun 16, 2016, at 12:06 AM, Robert Widmann <devteam.codafi@gmail.com> wrote:

But the proposal does not specify that and that is not how swift's access control mechanisms currently work, unfortunately. A private aggregate must have private members, and those members are subject to private access whether annotated or not.

On top of that, you break containment this way. A private member is not supposed to be visible outside of its current declaration. An aggregate full of private members similarly. You can see the aggregate, but you cannot see its members. If we relax this, then private is no different from fileprivate and we should just stick to our current tri-valued access control system.

~Robert Widmann

2016/06/15 23:04、Jonathan Hull via swift-evolution <swift-evolution@swift.org> のメッセージ:

My understanding of the proposal was that the unannotated properties/methods inside of a scope have the same *visibility* as their surrounding scope, or internal, whichever is less.

That is slightly different than having the same access level. Thus:

private struct Outer {
   var inner:Int
}

is different than:

private struct Outer {
   private var inner:Int
}

In the first, inner is accessible precisely everywhere where Outer is accessible. In the second, inner is only accessible within Outer itself. It is important that we have the first behavior for unannotated inner, because there is no other way to spell it.

That is my understanding of the intent of SE-0025, even if the exact wording is confusing.

Thanks,
Jon

P.S. I would personally like to see unannotated properties/methods inside of a scope have the same visibility as their surrounding scope. Full stop. End of sentence. (It seems to me like the special handling of internal is what is causing the confusion here). That is what I would expect the behavior to be if I didn’t know. That isn’t what was written in the proposal though...

While implementing SE-0025 (fileprivate), I noticed an interesting bug in the proposal. Under the implementation outlined there, any top-level structure, class, or enum declared private cannot possibly be instantiated and so cannot be used in any way. Because of this, private top-level declarations are more often than not blown away entirely by the compiler for being unused. It seems strange to me to allow a key language feature to act solely as a hint to the optimizer to reduce the size of your binary. Perhaps the restrictions around private needs to be relaxed or the line between fileprivate and private needs to be investigated again by the community before inclusion in the language.

Thoughts?

~Robert Widmann

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


(Jon Hull) #5

From the Impact portion of the proposal:

The existing code will need to rename private to fileprivate to achieve the same semantics. In many cases the new meaning of private is likely to compile as well and the code will then run exactly as before.

I believe the second sentence refers to the case where fileprivate and private are the same at the top level. I agree that the proposal is a bit vaguely/ambiguously written, but it in no way precludes the behavior everyone is saying was intended.

I know the current implementation just gives unannotated members the same access modifier as the outer scope’s, but that is an implementation detail. Furthermore it is entirely consistent with the interpretation given above in the case with only “fileprivate”, “internal”, and “public” scopes. It is only when we add the new “private” scope that there is a difference.

We have an ambiguous proposal which can be read in two different ways, but one of those ways is unworkable (the bug you mentioned), so I see no problem in interpreting it the other way (which just so happens to be the interpretation everyone says was intended) and moving forward. It is entirely consistent with the proposal.

~Robert Widmann

2016/06/16 0:29、Jonathan Hull <jhull@gbis.com> のメッセージ:

They happen to be the same at the top level, but they are very different when dealing with nested types…

A private member is visible inside it’s containing scope. For the top-level, that is the file. For a nested type, that is the outer type.

A wonderful idea, but not in the proposal. In fact, the singular example given therein runs directly counter to this idea by explicitly showing the scoping behavior of a private member.

Chis Lattner’s response to the initial proposal (before the name fileprivate was chosen):

Per Doug’s email, the core team agrees we should make a change here, but would like some bikeshedding to happen on the replacement name for private.

To summarize the place we’d like to end up:

- “public” -> symbol visible outside the current module.
- “internal” -> symbol visible within the current module.
- unknown -> symbol visible within the current file.
- “private” -> symbol visible within the current declaration (class, extension, etc).

The rationale here is that this aligns Swift with common art seen in other languages, and that many people using private today don’t *want* visibility out of their current declaration. It also encourages “extension oriented programming”, at least it will when some of the other restrictions on extensions are lifted. We discussed dropping the third one entirely, but think it *is* a useful and important level of access control, and when/if we ever get the ability to write unit tests inside of the file that defines the functionality, they will be a nicer solution to <at> testable.

As you can see the definition of “unknown” (now fileprivate) and “private” are exactly what I said. Many people wanted to name the new private “scoped” or “local" because of the way it worked, though “private” won in the end. As you see, they thought of getting rid of fileprivate, but decided it was necessary.

Then we should amend the proposal posthaste!

Basically, what I am saying here is that the intent is clear from the context (and original discussion) around the proposal. We all seem to agree about what needs to happen behavior-wise. At most this is a bug-fix, and shouldn’t require a full rehashing on evolution.

Thanks,
Jon

···

On Jun 16, 2016, at 12:35 AM, Robert Widmann <devteam.codafi@gmail.com> wrote:


(Robert Widmann) #6

That is for migration. It does not affect the semantics of private at any level, it merely explains how we should go about the initial transition. "In many cases" private being equivalent to fileprivate could be read that way, but given the rest of the proposal I didn't take any artistic freedoms and don't believe we should without clarification.

~Robert Widmann

2016/06/16 2:00、Jonathan Hull <jhull@gbis.com> のメッセージ:

···

From the Impact portion of the proposal:

The existing code will need to rename private to fileprivate to achieve the same semantics. In many cases the new meaning of private is likely to compile as well and the code will then run exactly as before.

I believe the second sentence refers to the case where fileprivate and private are the same at the top level. I agree that the proposal is a bit vaguely/ambiguously written, but it in no way precludes the behavior everyone is saying was intended.

I know the current implementation just gives unannotated members the same access modifier as the outer scope’s, but that is an implementation detail. Furthermore it is entirely consistent with the interpretation given above in the case with only “fileprivate”, “internal”, and “public” scopes. It is only when we add the new “private” scope that there is a difference.

We have an ambiguous proposal which can be read in two different ways, but one of those ways is unworkable (the bug you mentioned), so I see no problem in interpreting it the other way (which just so happens to be the interpretation everyone says was intended) and moving forward. It is entirely consistent with the proposal.

On Jun 16, 2016, at 12:35 AM, Robert Widmann <devteam.codafi@gmail.com> wrote:
~Robert Widmann

2016/06/16 0:29、Jonathan Hull <jhull@gbis.com> のメッセージ:

They happen to be the same at the top level, but they are very different when dealing with nested types…

A private member is visible inside it’s containing scope. For the top-level, that is the file. For a nested type, that is the outer type.

A wonderful idea, but not in the proposal. In fact, the singular example given therein runs directly counter to this idea by explicitly showing the scoping behavior of a private member.

Chis Lattner’s response to the initial proposal (before the name fileprivate was chosen):

Per Doug’s email, the core team agrees we should make a change here, but would like some bikeshedding to happen on the replacement name for private.

To summarize the place we’d like to end up:

- “public” -> symbol visible outside the current module.
- “internal” -> symbol visible within the current module.
- unknown -> symbol visible within the current file.
- “private” -> symbol visible within the current declaration (class, extension, etc).

The rationale here is that this aligns Swift with common art seen in other languages, and that many people using private today don’t *want* visibility out of their current declaration. It also encourages “extension oriented programming”, at least it will when some of the other restrictions on extensions are lifted. We discussed dropping the third one entirely, but think it *is* a useful and important level of access control, and when/if we ever get the ability to write unit tests inside of the file that defines the functionality, they will be a nicer solution to <at> testable.

As you can see the definition of “unknown” (now fileprivate) and “private” are exactly what I said. Many people wanted to name the new private “scoped” or “local" because of the way it worked, though “private” won in the end. As you see, they thought of getting rid of fileprivate, but decided it was necessary.

Then we should amend the proposal posthaste!

Basically, what I am saying here is that the intent is clear from the context (and original discussion) around the proposal. We all seem to agree about what needs to happen behavior-wise. At most this is a bug-fix, and shouldn’t require a full rehashing on evolution.

Thanks,
Jon


(Jon Hull) #7

Ok, I guess we will wait for the core team (or perhaps Ilya) to return and advise then…

Thanks,
Jon

···

On Jun 16, 2016, at 7:33 AM, Robert Widmann <devteam.codafi@gmail.com> wrote:

That is for migration. It does not affect the semantics of private at any level, it merely explains how we should go about the initial transition. "In many cases" private being equivalent to fileprivate could be read that way, but given the rest of the proposal I didn't take any artistic freedoms and don't believe we should without clarification.

~Robert Widmann

2016/06/16 2:00、Jonathan Hull <jhull@gbis.com <mailto:jhull@gbis.com>> のメッセージ:

From the Impact portion of the proposal:

The existing code will need to rename private to fileprivate to achieve the same semantics. In many cases the new meaning of private is likely to compile as well and the code will then run exactly as before.

I believe the second sentence refers to the case where fileprivate and private are the same at the top level. I agree that the proposal is a bit vaguely/ambiguously written, but it in no way precludes the behavior everyone is saying was intended.

I know the current implementation just gives unannotated members the same access modifier as the outer scope’s, but that is an implementation detail. Furthermore it is entirely consistent with the interpretation given above in the case with only “fileprivate”, “internal”, and “public” scopes. It is only when we add the new “private” scope that there is a difference.

We have an ambiguous proposal which can be read in two different ways, but one of those ways is unworkable (the bug you mentioned), so I see no problem in interpreting it the other way (which just so happens to be the interpretation everyone says was intended) and moving forward. It is entirely consistent with the proposal.

On Jun 16, 2016, at 12:35 AM, Robert Widmann <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> wrote:
~Robert Widmann

2016/06/16 0:29、Jonathan Hull <jhull@gbis.com <mailto:jhull@gbis.com>> のメッセージ:

They happen to be the same at the top level, but they are very different when dealing with nested types…

A private member is visible inside it’s containing scope. For the top-level, that is the file. For a nested type, that is the outer type.

A wonderful idea, but not in the proposal. In fact, the singular example given therein runs directly counter to this idea by explicitly showing the scoping behavior of a private member.

Chis Lattner’s response to the initial proposal (before the name fileprivate was chosen):

Per Doug’s email, the core team agrees we should make a change here, but would like some bikeshedding to happen on the replacement name for private.

To summarize the place we’d like to end up:

- “public” -> symbol visible outside the current module.
- “internal” -> symbol visible within the current module.
- unknown -> symbol visible within the current file.
- “private” -> symbol visible within the current declaration (class, extension, etc).

The rationale here is that this aligns Swift with common art seen in other languages, and that many people using private today don’t *want* visibility out of their current declaration. It also encourages “extension oriented programming”, at least it will when some of the other restrictions on extensions are lifted. We discussed dropping the third one entirely, but think it *is* a useful and important level of access control, and when/if we ever get the ability to write unit tests inside of the file that defines the functionality, they will be a nicer solution to <at> testable.

As you can see the definition of “unknown” (now fileprivate) and “private” are exactly what I said. Many people wanted to name the new private “scoped” or “local" because of the way it worked, though “private” won in the end. As you see, they thought of getting rid of fileprivate, but decided it was necessary.

Then we should amend the proposal posthaste!

Basically, what I am saying here is that the intent is clear from the context (and original discussion) around the proposal. We all seem to agree about what needs to happen behavior-wise. At most this is a bug-fix, and shouldn’t require a full rehashing on evolution.

Thanks,
Jon