[swift-evolution] [Pitch] consistent public access modifiers
xiaodi.wu at gmail.com
Wed Feb 8 17:48:45 CST 2017
I agree very much with rationalizing access levels, but I'm not sure I like
this proposal for public vs. closed. How would the compiler stop me from
editing my own code if something is closed? The answer must be that it
can't, so I can't see it as a co-equal to open but rather simply a
statement of intention. Therefore I think use cases for the proposed
behavior of closed would be better served by annotations and proper
As this change didn't seem in scope for Swift 4 phase 1, I've held off on
discussing my own thoughts on access levels. The idea I was going to
propose in phase 2 was to have simply open and public enums (and
protocols). I really think that completes access levels in a rational way
without introducing another keyword.
On Wed, Feb 8, 2017 at 17:05 Matthew Johnson via swift-evolution <
swift-evolution at swift.org> wrote:
> I’ve been thinking a lot about our public access modifier story lately in
> the context of both protocols and enums. I believe we should move further
> in the direction we took when introducing the `open` keyword. I have
> identified what I think is a promising direction and am interested in
> feedback from the community. If community feedback is positive I will
> flesh this out into a more complete proposal draft.
> Background and Motivation:
> In Swift 3 we had an extended debate regarding whether or not to allow
> inheritance of public classes by default or to require an annotation for
> classes that could be subclassed outside the module. The decision we
> reached was to avoid having a default at all, and instead make `open` an
> access modifier. The result is library authors are required to consider
> the behavior they wish for each class. Both behaviors are equally
> convenient (neither is penalized by requiring an additional boilerplate-y
> A recent thread (
> discussed a similar tradeoff regarding whether public enums should commit
> to a fixed set of cases by default or not. The current behavior is that
> they *do* commit to a fixed set of cases and there is no option (afaik) to
> modify that behavior. The Library Evolution document (
> suggests a desire to change this before locking down ABI such that public
> enums *do not* make this commitment by default, and are required to opt-in
> to this behavior using an `@closed` annotation.
> In the previous discussion I stated a strong preference that closed enums
> *not* be penalized with an additional annotation. This is because I feel
> pretty strongly that it is a design smell to: 1) expose cases publicly if
> consumers of the API are not expected to switch on them and 2) require
> users to handle unknown future cases if they are likely to switch over the
> cases in correct use of the API.
> The conclusion I came to in that thread is that we should adopt the same
> strategy as we did with classes: there should not be a default.
> There have also been several discussions both on the list and via Twitter
> regarding whether or not we should allow closed protocols. In a recent
> Twitter discussion Joe Groff suggested that we don’t need them because we
> should use an enum when there is a fixed set of conforming types. There
> are at least two reasons why I still think we *should* add support for
> closed protocols.
> As noted above (and in the previous thread in more detail), if the set of
> types (cases) isn’t intended to be fixed (i.e. the library may add new
> types in the future) an enum is likely not a good choice. Using a closed
> protocol discourages the user from switching and prevents the user from
> adding conformances that are not desired.
> Another use case supported by closed protocols is a design where users are
> not allowed to conform directly to a protocol, but instead are required to
> conform to one of several protocols which refine the closed protocol.
> Enums are not a substitute for this use case. The only option is to resort
> to documentation and runtime checks.
> This proposal introduces the new access modifier `closed` as well as
> clarifying the meaning of `public` and expanding the use of `open`. This
> provides consistent capabilities and semantics across enums, classes and
> `open` is the most permissive modifier. The symbol is visible outside the
> module and both users and future versions of the library are allowed to add
> new cases, subclasses or conformances. (Note: this proposal does not
> introduce user-extensible `open` enums, but provides the syntax that would
> be used if they are added to the language)
> `public` makes the symbol visible without allowing the user to add new
> cases, subclasses or conformances. The library reserves the right to add
> new cases, subclasses or conformances in a future version.
> `closed` is the most restrictive modifier. The symbol is visible publicly
> with the commitment that future versions of the library are *also*
> prohibited from adding new cases, subclasses or conformances.
> Additionally, all cases, subclasses or conformances must be visible outside
> the module.
> Note: the `closed` modifier only applies to *direct* subclasses or
> conformances. A subclass of a `closed` class need not be `closed`, in fact
> it may be `open` if the design of the library requires that. A class that
> conforms to a `closed` protocol also need not be `closed`. It may also be
> `open`. Finally, a protocol that refines a `closed` protocol need not be
> `closed`. It may also be `open`.
> This proposal is consistent with the principle that libraries should
> opt-in to all public API contracts without taking a position on what that
> contract should be. It does this in a way that offers semantically
> consistent choices for API contract across classes, enums and protocols.
> The result is that the language allows us to choose the best tool for the
> job without restricting the designs we might consider because some kinds of
> types are limited with respect to the `open`, `public` and `closed`
> semantics a design might require.
> Source compatibility:
> This proposal affects both public enums and public protocols. The current
> behavior of enums is equivalent to a `closed` enum under this proposal and
> the current behavior of protocols is equivalent to an `open` protocol under
> this proposal. Both changes allow for a simple mechanical migration, but
> that may not be sufficient given the source compatibility promise made for
> Swift 4. We may need to identify a multi-release strategy for adopting
> this proposal.
> Brent Royal-Gordon suggested such a strategy in a discussion regarding
> closed protocols on Twitter:
> * In Swift 4: all unannotated public protocols receive a warning, possibly
> with a fix-it to change the annotation to `open`.
> * Also in Swift 4: an annotation is introduced to opt-in to the new
> `public` behavior. Brent suggested `@closed`, but as this proposal
> distinguishes `public` and `closed` we would need to identify something
> else. I will use `@annotation` as a placeholder.
> * Also In Swift 4: the `closed` modifier is introduced.
> * In Swift 5 the warning becomes a compiler error. `public protocol` is
> not allowed. Users must use `@annotation public protocol`.
> * In Swift 6 `public protocol` is allowed again, now with the new
> semantics. `@annotation public protocol` is also allowed, now with a
> warning and a fix-it to remove the warning.
> * In Swift 7 `@annotation public protocol` is no longer allowed.
> A similar mult-release strategy would work for migrating public enums.
> swift-evolution mailing list
> swift-evolution at swift.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution