[swift-evolution] [Discussion] A Problem With SE-0025?
Brent Royal-Gordon
brent at architechies.com
Thu Jun 16 02:09:23 CDT 2016
> Charles we've diverged from the actual issue at hand to nitpick my English. Read the code (that std::min tho!). We have a problem here and no obvious solution that doesn't involve special-casing parts of this proposal.
I think it might be more helpful to think of it this way:
1. The mental model has generally been that, absent a specific access control keyword, a member is as visible as the enclosing type, except that it is never automatically `public`.
2. Because of the way the old public/internal/private access control model was defined, this was equivalent to applying the enclosing type's access control keyword to the member. Therefore, that was the implementation model chosen by the compiler.
3. However, now that we have a scope-dependent access control level, these two models provide divergent behavior, and we must use a different implementation model. (We know that the old implementation model is not an accurate match for the mental model because scoped `private` provides sensical behavior in the mental model, but nonsensical behavior in the implementation model.)
4. We understand what the effect of this new implementation model *should* be: The members of the private type should be as visible as the private type, unless they are themselves marked private.
5. However, we're not exactly sure how this new model should be implemented, and core team guidance is probably necessary. In particular, these children of `private` types have a somewhat mysterious new property: their visibility cannot be accurately described by any existing access control keyword. It's not clear how to cope with that. (The easiest solution―add a new access control level which is basically "private to me and my parent"―won't do the trick: members of nested types, like `z` in `private struct X { struct Y { var z: Int } }`, should be visible two levels up. The visibility of these members is genuinely complicated and context-specific.)
6. With the core team tied up at WWDC, you may want to temporarily forbid the use of `private` on a type and revisit the matter when people are less busy; if necessary, we could even ship Swift 3 that way. Or you may want to consider making a guess as to a good implementation model to apply. Two suggestions for alternate implementation models:
a. Introduce a `parent` access level, meaning "visible in scopes within this file where the parent is visible", which is between `fileprivate` and `private`. Just as `internal` is the maximum inherited access level, `parent` is the minimum, so the members of a `private` type would inherit `parent` visibility. `parent` might be an entirely compiler-internal concept, with no utterable access control keyword.
b. Instead of inheriting an access control modifier's visibility, always set unspecified ones to `internal`, but make sure they stay effectively invisible in scopes where their parent is not visible. Introduce a warning or error for *explicitly* specifying a modifier that exceeds the parent's visibility, but don't emit it for implicit `internal`s.
c. Combine the two: `parent` means "visible wherever the parent is, whether within this file or not, except not public", and is *always* the default access level if nothing else is specified. (`parent` doesn't fit neatly into the access control hierarchy, but on the other hand, it's the closest match to the mental model.)
A final note: I usually try not to complain about accepted proposals, but I'll make an exception this time. I pointed out during the discussion and review that this proposal was unclear and that scoped `private` was quite different from our existing access control behaviors. I won't claim that I predicted this problem, but I'm not surprised to find that we're running into it.
--
Brent Royal-Gordon
Architechies
More information about the swift-evolution
mailing list