[swift-evolution] [Discussion] A Problem With SE-0025?

John McCall rjmccall at apple.com
Thu Jun 30 01:34:14 CDT 2016


> On Jun 29, 2016, at 7:07 PM, Xiaodi Wu via swift-evolution <swift-evolution at swift.org> wrote:
> 
> [Resending with fewer recipients]
> 
> On Wed, Jun 29, 2016 at 8:55 PM, Jordan Rose <jordan_rose at apple.com <mailto:jordan_rose at apple.com>> wrote:
> Updated in https://github.com/apple/swift-evolution/pull/396 <https://github.com/apple/swift-evolution/pull/396>. Thanks again, everyone!
>  
> As usual, a thoughtful result from the core team. Curious, though, where does the following statement come into play?
> 
> "The access level of a conformance concerning a `private` type or protocol is considered to be `fileprivate` rather than `private`."

I think the internal representation may be leaking out.  I believe this is the right basic approach for formalizing the language rules here:

1. A scope S has access to a declaration D if S has access to the scope S_D in which D is declared and:
  - if D is explicitly declared 'private', S is equal to S_D or lexically nested within S_D,
  - if D is explicitly declared 'fileprivate', S appears within the same file as S_D,
  - if D is explicitly declared 'internal', S appears within the same module as S_D, or
  - if D lacks an explicit access specifier, S appears within the same module as S_D or S_D is a public extension (*).
(*) I believe this special case rule about public extensions is correct for the current model.  I'm not sure it's a good idea, though.

2. A scope S has access to a scope T if:
  - S is equal to T or is lexically nested within it,
  - T is a declaration D and S has access to D, or
  - T is a file scope.

3. A declaration D shall not use in its signature any declaration D_sig for which there potentially exists a scope S such that S has access to D but not D_sig.  The signature of a declaration includes:
  - the explicit type of a function, initializer, variable, or constant declaration; or its inferred type (fully "desugared", e.g. ignoring all type aliases) if an explicit type is not given
  - the underlying type of a typealias or associatedtype declaration
  - the superclass type of a class declaration
  - the conformance list of a class, struct, enum, protocol, or extension declaration
  - the generic parameters and constraints of a generic declaration
  - etc.

Formally, there's no need to decide the "real" or "effective" access modifier for a declaration.  Conveniently (and not coincidentally), these rules do end up being equivalent to computing an effective access level by just merging information down from the lexical container, but that's emergent, not fundamental, so don't put too much energy into whether the emergent access level "makes sense" as a description.

John.

>  
> Jordan
> 
>> On Jun 29, 2016, at 16:51, Jordan Rose <jordan_rose at apple.com <mailto:jordan_rose at apple.com>> wrote:
>> 
>> I just attended a core team meeting where this whole thing was discussed, and will update our amendment <https://github.com/apple/swift-evolution/pull/383> tonight. But in short:
>> 
>> - The default access level will be 'internal' everywhere*. The compiler will not warn if the access-as-written is broader than necessary. Motivation: it should be possible to design a type's API as if it had more access than it currently does.
>> 
>> * except in extensions, see below
>> 
>> - The complicated "rule 2" from the amendment stands, but possibly in a form that isn't specific to 'fileprivate':
>> 
>>> A non-private method, initializer, subscript, property, or typealias may still have a type that references `private` declarations if (1) the non-private declaration is a member of a private type, and (2) all referenced `private` declarations are defined within an enclosing lexical scope. That is, it is legal for a non-private member within a `private` type to have a type that is formally `private` if it would be legal for a `private` declaration in the parent scope to have that type.
>> 
>> 
>> As Xiaodi pointed out, this could be even broader, to say that an internal member may reference a fileprivate type if the member is itself defined within a fileprivate type, because it's still safe. That would look like this:
>> 
>>> A member may not have a type that references any declarations that aren't accessible wherever the member is accessible.
>> 
>> I'm concerned about that being too permissive, though. I still want this to be considered an error:
>> 
>> fileprivate struct Foo {
>>   fileprivate typealias Bar = Int
>>   internal func baz() -> Bar { … }
>> }
>> 
>> - An access modifier on an extension has been ruled to indicate the desired scope, not the desired access. Therefore, members within a `private extension` will be `fileprivate`. (We're only really getting away with this because we don't allow extensions anywhere but at the top level, though if we had nested extensions we'd probably consider them scoped anyway.)
>> 
>> - We are not looking at renaming either 'fileprivate' or 'private' for Swift 3.
>> 
>> - All this has been ruled not to need a formal review.
>> 
>> Thanks everyone for getting us to this point. It's definitely different from what I would have come up with on my own or just collaborating with Robert, so you can all count yourselves as contributors to this one. :-)
>> 
>> Jordan
>> 
>> P.S. If you see further issues here I'd still like to hear them; if you're unclear on any points after I've updated the pull request <https://github.com/apple/swift-evolution/pull/383>, I'm happy to go over them again.
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160629/360af2e6/attachment.html>


More information about the swift-evolution mailing list