Sent from my iPad

> On Jun 15, 2016, at 5:17 PM, Robert Widmann <[email protected]> wrote:
> 
> I await their opinions, but even with that change we still have a problem 
> with the philosophy here.  The motivation behind the fileprivate/private 
> distinction is, as you say in the proposal "[a] reliable way to hide 
> implementation details...".  Why would you want any members you're trying to 
> hide to be visible in any scope other than the one you create with the decl 
> (which is, without a doubt, also a lexical scope)?  It is analogous with 
> other access control levels: a public outer decl implies public inner members 
> just as a fileprivate one implies fileprivate inner members.  Is it not 
> antithetical to being able to hide things if they remain visible despite the 
> outer decl declaring itself supposedly being sealed?  In your examples, you 
> declare private members that you do not wish to leak into top level scope 
> because they are, after all, supposedly hidden.  Should the same semantics 
> you have given not also apply to private decls no matter where they lie? 
> 

Sorry, missed the example in my last reply.

> Should this compile:
> 
> private struct Outer {
>     let inner = Inner()
> }
> 
> Outer().inner

Aside from the fact that you can't write a standalone statement at the top 
level of a file and it isn't clear what 'Inner' is, yes.  This would be valid:

private struct Outer {
    struct Inner {}
    let inner = Inner()
}

private let inner = Outer().inner

Note that the top level 'inner' must be 'private' or 'fileprivate' because 
'Inner' is not visible outside the file.

> 
> If this shouldn't:
> 
> struct Outer {
>     private let inner = Inner()
> }
> 
> extension Outer {
>     var inner2 : Inner { return self.inner }
> }

The extension introduces a new scope so this is not valid.

> 
> Visibility being a function of scope, lexical or otherwise, seems too coarse 
> a metric for access control in general without further clarification of what 
> the definition of "hidden" is.

The lexical scope of the declaration itself (not a scope introduced by the 
declaration) is perfectly clear.  You may not like it or agree that it is 
desirable but it certainly isn't ambiguous.

> 
> ~Robert Widmann
> 
> 2016/06/15 12:38、Matthew Johnson <[email protected]> のメッセージ:
> 
>> 
>>> On Jun 15, 2016, at 2:29 PM, Robert Widmann <[email protected]> 
>>> wrote:
>>> 
>>> The meaning of private according to the proposal is not scope-dependent, it 
>>> is decl-dependent.  The mental gymnastics we are both going through right 
>>> now are not in the proposal.  I would like them to be.
>> 
>> I agree that the proposal is too sparse on the details and that is the 
>> source of the confusion.  
>> 
>> Ilya wanted me to write this proposal and only did it himself because I 
>> didn’t have time to do it as quickly as he wanted.  I know what the original 
>> intent of the proposal was (I can’t speak for the core team on their mental 
>> model of it when they accepted it).
>> 
>> That said, the title of the proposal is “scoped access level” and the 
>> detailed design says "visible only within that lexical scope”.  And the 
>> entire discussion was always about lexical scope.  I believe the reason the 
>> “proposed solution” section says “current declaration” is because *most* 
>> lexical scopes are introduced by a declaration.  That is sloppy language 
>> that should have been cleaned up prior to review.
>> 
>> I appreciate you working on implementing this.  I also understand if you 
>> want to hold off until the core team can chime in on the semantics they 
>> intend.  
>> 
>> Matthew
>> 
>>> 
>>> ~Robert Widmann
>>> 
>>> 2016/06/15 12:26、Matthew Johnson <[email protected]> のメッセージ:
>>> 
>>>> 
>>>>> On Jun 15, 2016, at 2:19 PM, Robert Widmann <[email protected]> 
>>>>> wrote:
>>>>> 
>>>>> We have diagnostics specifically to prohibit this case.  You cannot raise 
>>>>> the access level of members.
>>>>> 
>>>>> private struct Foo {
>>>>>     internal var x : String = ""
>>>>> }
>>>>> 
>>>>> warning: declaring an internal var for a private struct.
>>>>> 
>>>>> Hence, the highest allowable level of access for x is private and it 
>>>>> becomes invisible.
>>>>> 
>>>>> I would not like the compiler to synthesize this in my code, and if it 
>>>>> did I would like the proposal to say it will raise access levels of 
>>>>> members as you would like it to.
>>>> 
>>>> That diagnostic is a good thing.  I am not suggesting that you to 
>>>> disregard it.
>>>> 
>>>> What you are missing is that the meaning of `private` is scope-dependent.  
>>>> The following example is perfectly valid:
>>>> 
>>>> private struct Foo {
>>>>     fileprivate var x : String = “”
>>>> }
>>>> 
>>>> `fileprivate` inside `Foo` specifies the same visibility as `private` at 
>>>> the top level, thus we are not “raising" the visibility of the member.  If 
>>>> no modifier is provided for `x` it receives the same visibility as its 
>>>> containing type (up to `internal`).
>>>> 
>>>> Consider another example:
>>>> 
>>>> struct Foo {
>>>>     private struct Bar {
>>>>         var x : String = “”
>>>>     }
>>>> }
>>>> 
>>>> In this example we *cannot* mark `x` as `fileprivate` because that *would* 
>>>> raise the visibility of `x` beyond that of `Bar`.  `Bar` is only visible 
>>>> inside `Foo`, not at file scope.  This means that `x` also has visibility 
>>>> throughout the lexical scope of `Foo`, but not outside of it.
>>>> 
>>>> -Matthew
>>>> 
>>>> 
>>>>> 
>>>>> ~Robert Widmann
>>>>> 
>>>>> 2016/06/15 12:14、Matthew Johnson <[email protected]> のメッセージ:
>>>>> 
>>>>>> 
>>>>>>> On Jun 15, 2016, at 2:04 PM, Robert Widmann <[email protected]> 
>>>>>>> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> 2016/06/15 11:47、Matthew Johnson <[email protected]> のメッセージ:
>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Jun 15, 2016, at 1:37 PM, Robert Widmann 
>>>>>>>>> <[email protected]> wrote:
>>>>>>>>> 
>>>>>>>>> The scope of the *declaration* is not the issue.  The scope of its 
>>>>>>>>> *members* is.
>>>>>>>> 
>>>>>>>> Let’s consider an example:
>>>>>>>> 
>>>>>>>> private struct Foo {
>>>>>>>>   var bar: Int
>>>>>>>> }
>>>>>>>> 
>>>>>>>> // elsewhere in the same file:
>>>>>>>> var foo = Foo(bar: 42)
>>>>>>>> foo.bar = 44
>>>>>>>> 
>>>>>>>> `Foo` is declared private.  Private for this declaration is at the 
>>>>>>>> file scope.  The `bar` member has no access modifier so it has the 
>>>>>>>> same visibility as the struct itself, which is file scope.  This will 
>>>>>>>> also be true of the implicitly synthesized memberwise initializer.  
>>>>>>> 
>>>>>>> No, it is also private.  It does not inherit its parent scope because, 
>>>>>>> following the letter of the proposal, that symbol will only be visible 
>>>>>>> within the current declaration.  We cannot arbitrarily break access 
>>>>>>> control rules because it is convenient in one special case. 
>>>>>>> 
>>>>>>>> 
>>>>>>>> This means that it is possible to initialize `foo` with a newly 
>>>>>>>> constructed instance of `Foo` and to modify the `bar` member anywhere 
>>>>>>>> else in the same file.
>>>>>>> 
>>>>>>> bar is not visible here.  If it were you could break access control 
>>>>>>> rules.
>>>>>>> 
>>>>>>>> 
>>>>>>>> If `bar` was also declared `private` this would not be possible as its 
>>>>>>>> visibility would be restricted to the surrounding scope of the initial 
>>>>>>>> declaration of `Foo`.  This means `Foo` would need to provide an 
>>>>>>>> explicit initializer or factory method with `fileprivate` visibility 
>>>>>>>> in order to be usable.
>>>>>>> 
>>>>>>> bar is private.  Declarations within Foo cannot decide to raise that 
>>>>>>> access level to make themselves more visible.  If this should be the 
>>>>>>> case, the proposal must be amended as much.
>>>>>>> 
>>>>>>>> 
>>>>>>>> Members with no explicit access modifier should have the same 
>>>>>>>> *visibility* as their containing type (with a maximum implicit 
>>>>>>>> visibility of internal), not the same *modifier* as their containing 
>>>>>>>> type.  The only case where there is a distinction is the new `private` 
>>>>>>>> visibility.  Maybe that is what is causing the confusion?
>>>>>>> 
>>>>>>> That is not what the proposal says.  The proposal says it is invisible 
>>>>>>> outside the current decl, which is the containing structure here.
>>>>>> 
>>>>>> The access modifier is applied to `Foo`, not `bar`.  `Foo` is visible in 
>>>>>> the scope of the “current declaration” (this is badly worded - it should 
>>>>>> say current scope, which is the file).  Because `Foo` has a visibility 
>>>>>> lower than `internal` the default visibility of its members match the 
>>>>>> visibility of `Foo`, which again is the current scope: the file.  The 
>>>>>> detailed design section of the proposal is sparse, but it correctly uses 
>>>>>> the phrase "visible only within that lexical scope” rather than the less 
>>>>>> precise (in the case of top-level code) “current declaration”.
>>>>>> 
>>>>>> I didn’t write the proposal but I was very heavily involved in the 
>>>>>> discussions and IIRC I provided the original suggestion for introducing 
>>>>>> a scoped access modifier.
>>>>>> 
>>>>>> If my example was the following:
>>>>>> 
>>>>>> private struct Foo {
>>>>>>   private var bar: Int
>>>>>> }
>>>>>> 
>>>>>> Then what you are saying would be correct.  However, The example I 
>>>>>> showed did not provide an access modifier for `bar`.
>>>>>> 
>>>>>> You cannot just apply the same *access modifier* to members of the type 
>>>>>> that do not contain an access modifier.  You have to apply the same 
>>>>>> *visibility* (limited to internal).  When a type is marked as `private` 
>>>>>> in the lexical scope of the file, its unmodified members will be visible 
>>>>>> in the same lexical scope as the type itself (which is the file in the 
>>>>>> current example).
>>>>>> 
>>>>>> -Matthew
>>>>>> 
>>>>>>> 
>>>>>>>> 
>>>>>>>> Does this help?
>>>>>>>> 
>>>>>>>> -Matthew
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> ~Robert Widmann
>>>>>>>>> 
>>>>>>>>> 2016/06/15 11:36、Matthew Johnson <[email protected]> のメッセージ:
>>>>>>>>> 
>>>>>>>>>> The scope for a top-level declaration is the file itself.  This 
>>>>>>>>>> means that top-level declarations with `private` and `fileprivate` 
>>>>>>>>>> should have the same behavior.  They should not be uninstantiable or 
>>>>>>>>>> unusable.
>>>>>>>>>> 
>>>>>>>>>> -Matthew
>>>>>>>>>> 
>>>>>>>>>>> On Jun 15, 2016, at 1:31 PM, Robert Widmann via swift-evolution 
>>>>>>>>>>> <[email protected]> wrote:
>>>>>>>>>>> 
>>>>>>>>>>> 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
>>>>>>>>>>> [email protected]
>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to