<html><head><style>
body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        padding:1em;
        margin:auto;
        background:#fefefe;
}
h1, h2, h3, h4, h5, h6 {
        font-weight: bold;
}
h1 {
        color: #000000;
        font-size: 28pt;
}
h2 {
        border-bottom: 1px solid #CCCCCC;
        color: #000000;
        font-size: 24px;
}
h3 {
        font-size: 18px;
}
h4 {
        font-size: 16px;
}
h5 {
        font-size: 14px;
}
h6 {
        color: #777777;
        background-color: inherit;
        font-size: 14px;
}
hr {
        height: 0.2em;
        border: 0;
        color: #CCCCCC;
        background-color: #CCCCCC;
display: inherit;
}
p, blockquote, ul, ol, dl, li, table, pre {
        margin: 15px 0;
}
a, a:visited {
        color: #4183C4;
        background-color: inherit;
        text-decoration: none;
}
#message {
        border-radius: 6px;
        border: 1px solid #ccc;
        display:block;
        width:100%;
        height:60px;
        margin:6px 0px;
}
button, #ws {
        font-size: 12 pt;
        padding: 4px 6px;
        border-radius: 5px;
        border: 1px solid #bbb;
        background-color: #eee;
}
code, pre, #ws, #message {
        font-family: Monaco;
        font-size: 10pt;
        border-radius: 3px;
        background-color: #F8F8F8;
        color: inherit;
}
code {
        border: 1px solid #EAEAEA;
        margin: 0 2px;
        padding: 0 5px;
}
pre {
        border: 1px solid #CCCCCC;
        overflow: auto;
        padding: 4px 8px;
}
pre > code {
        border: 0;
        margin: 0;
        padding: 0;
}
#ws { background-color: #f8f8f8; }
.bloop_markdown table {
border-collapse: collapse;
font-family: Helvetica, arial, freesans, clean, sans-serif;
color: rgb(51, 51, 51);
font-size: 15px; line-height: 25px;
padding: 0; }
.bloop_markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.bloop_markdown table tr:nth-child(2n) {
background-color: #f8f8f8; }
.bloop_markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr th :first-child, table tr td :first-child {
margin-top: 0; }
.bloop_markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
.bloop_markdown blockquote{
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
hr {
display: inherit;
}
.bloop_markdown :first-child {
-webkit-margin-before: 0;
}
code, pre, #ws, #message {
font-family: Menlo, Consolas, Liberation Mono, Courier, monospace;
}
.send { color:#77bb77; }
.server { color:#7799bb; }
.error { color:#AA0000; }</style></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="bloop_markdown"><p>Hello Jordan, having a clear and constructive opinion like yours is much appreciated in this topic.</p>
<p>As a disclaimer, I haven’t followed the original topic about the new <code>open</code> access modifier that much last year. At day one, when Swift 3 was released, I noticed <code>open</code> everywhere in Apples libraries like <code>UIKit</code>. I quickly had a short glance on how it supposed to work, because I literally run into the issue where the <code>open</code> is prohibited on initializers, which felt odd. Then I had a closer look to the proposal and realized it’s by design; but it still feels strange, because <code>public-but-not-open</code> claims to disallow overriding a type member from module A in module B, where <code>open</code> removes that restriction. Later on thinking how neat the differentiation between <code>public</code> and <code>open</code> was I thought, because it’s an <code>ACCESS MODIFIER</code>, it should work with any type we had in swift. Okay it doesn’t work with value types because they don’t have any sub-typing relationship which the <em>client</em> of my module could create - that’s totally fine by me. At the end of that journey I remembered that I had some protocols which I had to make public before Swift 3 because it was an implementation detail. Also it was really interesting to see that non of my protocols were <code>open</code> by default after the migration process. At that point I tried to open these protocols where I thought the client should be able to conform to them, because <code>public</code> should mean <code>public-but-not-open</code> right? And this is how I hit the wall with this.</p>
<p>I felt I had to share my experience on this.</p>
<p>Now that you’ve mentioned an alternative for protocols, such as <code>@closed public</code>. IMHO this would be a really shame if this was the final decision for this issue.</p>
<ol>
<li><p>Iff we <em>ever</em> decide to bring sub-typing to value types, that would imply that we’d end up with <code>open class/struct/enum</code> vs. <code>@closed public protocol</code>, or even worse <code>open class</code> vs. <code>@closed public protocols/struct/enum</code>. It is simply saying inconsistent.</p></li>
<li><p>Having an exclusive access modifier for classes is simply not worth calling <code>open</code> an access modifier, because from the definitions it should affect all types and their members but not being exclusive to classes, otherwise it should have been <code>open public</code>, just like <code>final public</code> is.</p></li>
<li><p>Having an exclusive attribute for protocols, which <strong>only</strong> works with the <code>public</code> access modifier is nuts. Furthermore that would not only reserve the <code>@closed</code> attribute, but could potentially lead to even more inconsistency if we consider to add something like <code>@closed</code> to enums or elsewhere. In the current scenario <code>@closed public</code> has simply no other meaning than <code>public</code> on classes would have, but <code>public</code> would be <code>open</code> for protocols. o.O It definitely will become an origin of confusion at that point.</p></li>
</ol>
<p>I understand that this is somehow a breaking change, but currently <code>open</code> feels simply as a rushed decision from last year. In its current state I think it’s a regression.</p>
<p>P.S.: Please don’t blame me for my horrible English. ;)</p>
<p></p></div><div class="bloop_original_html"><style>body{font-family:Helvetica,Arial;font-size:13px}</style><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px; color: rgba(0,0,0,1.0); margin: 0px; line-height: auto;"><br></div> <br> <div id="bloop_sign_1486753594904865024" class="bloop_sign"><div style="font-family:helvetica,arial;font-size:13px">-- <br>Adrian Zubarev<br>Sent with Airmail</div></div> <br><p class="airmail_on">Am 10. Februar 2017 um 19:52:23, Jordan Rose via swift-evolution (<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>) schrieb:</p> <blockquote type="cite" class="clean_bq"><span><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="" applecontenteditable="true"><div></div><div>
<title></title>
<div class="">Hi, Matthew. Thank you for bringing up these issues.
I'm going to break my feedback up into separate messages, because I
think really the enum and protocol cases are unrelated. Open
classes refer to classes that can be subclassed from <i class="">clients</i> of the current module, and similarly open
protocols would be protocols that can be adopted from clients of
the current module. Public-but-not-open classes cannot be
subclassed from outside the current module, but they can still be
subclassed <i class="">within</i> the module. By contrast,
"open" enums can grow new cases <i class="">in new versions of the
library,</i> but clients still can't add cases. (That's not a
totally unreasonable feature to <i class="">ever</i> consider, but it's not the one we need
now.)</div>
<div class=""><br class=""></div>
<div class="">This message will talk about protocols (and a bit
about classes); I'll put my thoughts on enums in another
message.</div>
<div class=""><br class=""></div>
<div class="">I'm with you (and Adrian) in thinking
"public-but-not-open" protocols are useful. The Apple frameworks
have a good handful of these, for cases where a framework doesn't
want to tie itself to a particular type, but still wants to vend
something with certain operations. Public-but-not-open protocols
also allow for non-public <i class="">requirements,</i> i.e.
operations that every conforming type has but only the library
needs to call.</div>
<div class=""><br class=""></div>
<div class="">However, we still have a hurdle here: is this useful
enough to <i class="">change the defaults</i> for it? Another
way to implement this is to leave 'public' as is (with its
open-like behavior), but have an annotation to say that it can only
be conformed to from within the module. (`@closed public protocol
Foo`) This isn't necessarily what we would have done from the
start, but breaks between Swift 3 and Swift 4 have a higher bar to
clear than between Swift 2 and Swift 3.</div>
<div class=""><br class=""></div>
<div class="">It's worth noting that this can all be emulated by a
struct with a non-public field of protocol type and forwarding
operations, but that's a lot of extra work today. We want to make
the correct thing easy; in the face of writing a wrapper type, I
suspect many library authors would just give up and make the
protocol public.</div>
<div class=""><br class=""></div>
<div class="">I don't think the proposed "closed" for classes and
protocols is interesting. "No new subclasses/adopters" seems only
marginally useful for optimization, and not at all useful at a
semantic level. "public-but-not-open" is the interesting access
level.</div>
<div class=""><br class=""></div>
<div class="">That's about all I've got for protocols. Thanks again
for bringing it up.</div>
<div class="">Jordan</div>
<div class=""><br class=""></div>
<div class="">P.S. For classes, note that 'final' is essentially a
performance optimization at this point. I'm not even sure we should
bother displaying it in generated interfaces (although the
<i class="">compiler</i> should still be able to take
advantage of it in clients).</div>
<div class=""><br class=""></div>
<div class=""><br class=""></div>
<br class="">
<div>
<blockquote type="cite" class="">
<div class="">On Feb 8, 2017, at 15:05, Matthew Johnson via
swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">
<div class="">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.</div>
<div class=""><br class=""></div>
<div class=""><br class=""></div>
<div class="">Background and Motivation:</div>
<div class=""><br class=""></div>
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 annotation).
<div class=""><br class=""></div>
<div class="">A recent thread (<a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170206/031566.html</a>)
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 (<a href="https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums" class="">https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums</a>)
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.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class=""><br class=""></div>
<div class="">Proposal:</div>
<div class=""><br class=""></div>
<div class="">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
protocols.</div>
<div class=""><br class=""></div>
<div class="">`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)</div>
<div class=""><br class=""></div>
<div class="">`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.</div>
<div class=""><br class=""></div>
<div class="">`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.</div>
<div class=""><br class=""></div>
<div class="">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`.</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class=""><br class=""></div>
<div class="">Source compatibility:</div>
<div class=""><br class=""></div>
<div class="">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.</div>
<div class=""><br class=""></div>
<div class="">Brent Royal-Gordon suggested such a strategy in a
discussion regarding closed protocols on Twitter:</div>
<div class=""><br class=""></div>
<div class="">* In Swift 4: all unannotated public protocols
receive a warning, possibly with a fix-it to change the annotation
to `open`.</div>
<div class="">* 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.</div>
<div class="">* Also In Swift 4: the `closed` modifier is
introduced.</div>
<div class=""><br class=""></div>
<div class="">* In Swift 5 the warning becomes a compiler error.
`public protocol` is not allowed. Users must use
`@annotation public protocol`.</div>
<div class="">* 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.</div>
<div class="">* In Swift 7 `@annotation public protocol` is no
longer allowed.</div>
<div class=""><br class=""></div>
<div class="">A similar mult-release strategy would work for
migrating public enums.</div>
<div class=""><br class=""></div>
<div class=""><br class=""></div>
</div>
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div>
</blockquote>
</div>
<br class="">
_______________________________________________<br>swift-evolution mailing list<br>swift-evolution@swift.org<br>https://lists.swift.org/mailman/listinfo/swift-evolution<br></div></div></span></blockquote></div><div class="bloop_markdown"><p></p></div></body></html>