<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 10 Aug 2017, at 02:42, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">:-) As you've all noted, there are some&nbsp;conflicting concerns for the default:</div><div class=""><br class=""></div><div class="">- Source compatibility: the existing behavior for an unannotated enum is "closed".</div><div class="">- Intuition: if you show someone an enum without an explicit annotation, they'll probably expect they can switch over it. (I'm going to say this is why Zach calls it a "sensible default".)</div><div class="">- Consistency: switches on an enum in the same module can always be exhaustive, so having it be different across modules is a bit annoying. (But 'public' already acts like this.)</div><div class=""><br class=""></div><div class="">vs.</div><div class=""><br class=""></div><div class="">- Library evolution: the default should promise less, so that you have the opportunity to change it.</div><div class="">- Flexibility: you can emulate an exhaustive switch with a non-exhaustive switch using fatalError, but not the other way around.</div><div class=""><br class=""></div><div class="">All of this is why I suggested it be an explicit annotation in either direction, but Matthew brought up the "keyword soup" problem—if you have to write (say) "public finite enum" and "public infinite enum", but would never write "private finite enum" or "private infinite enum", <i class="">something</i>&nbsp;is redundant here. Still, I'm uncomfortable with the default case being the one that constrains library authors, so at <i class="">least</i>&nbsp;for binary frameworks (those compiled "with resilience") I would want that to be explicit. That brings us to one more concern: how different should binary frameworks be from source frameworks?</div></div></div></blockquote><div><br class=""></div><div>In terms of intuition and consistency, I think we should really try to learn from the simplicity of public/open:</div><div><br class=""></div><div>* When <b class="">internal</b>, classes are sub-classable by default for <b class="">convenience</b>, but can be closed with the <b class="">final</b> keyword</div><div>* When <b class="">public</b>, classes are closed to sub-classing for <b class="">safety</b>, but can be opened up with the <b class="">open</b> keyword (which implies public).</div><div><br class=""></div><div>If we try to mirror this behaviour (the keywords are just suggestions, not important):</div><div><br class=""></div><div>* When <b class="">internal</b>, enums are exhaustive by default for <b class="">convenience</b>, but can be opened-up with the <b class="">partial</b> keyword</div><div>* When <b class="">public, </b>enums are non-exhaustive by default for <b class="">safety</b>, but can be made exhaustive with the&nbsp;<b class="">exhaustive</b>&nbsp;keyword (which implies public).</div><div><br class=""></div><div>David.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Jordan</div><div class=""><br class=""></div><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Aug 9, 2017, at 08:19, Zach Waldowski via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class="">


<title class=""></title>

<div class=""><div style="font-family:Arial;" class="">I disagree. Closed is indeed the stronger guarantee, but APIs are designed differently in Swift; closed is a sensible default. We shouldn’t need to define new keywords and increase the surface area of the language for something that has verisimilitude with the existing open syntax.<br class=""></div>
<div style="font-family:Arial;" class=""><br class=""></div>
<div id="sig20055365" class=""><div class="signature"><span class="font" style="font-family:arial, sans-serif, sans-serif">Sincerely,</span><span class="font" style="font-family:arial, sans-serif, sans-serif"></span><br class=""></div>
<div class="signature"><span class="font" style="font-family:arial, sans-serif, sans-serif">&nbsp; Zachary Waldowski</span><span class="font" style="font-family:arial, sans-serif, sans-serif"></span><br class=""></div>
<div class="signature"><span class="font" style="font-family:arial, sans-serif, sans-serif">&nbsp;&nbsp;</span><a href="mailto:zach@waldowski.me" class=""><span class="font" style="font-family:arial, sans-serif, sans-serif">zach@waldowski.me</span></a><span class="font" style="font-family:arial, sans-serif, sans-serif"></span><br class=""></div>
<div style="font-family:Arial;" class=""><br class=""></div>
</div>
<div class=""><br class=""></div>
<div class="">On Wed, Aug 9, 2017, at 06:23 AM, David Hart via swift-evolution wrote:<br class=""></div>
<blockquote type="cite" class=""><div style="font-family:Arial;" class=""><br class=""></div>
<div class=""><div style="font-family:Arial;" class=""><br class=""></div>
<div style="font-family:Arial;" class="">On 9 Aug 2017, at 09:21, Adrian Zubarev via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div>
</div>
<blockquote type="cite" class=""><div class="">Hi Jordan, is that only me or haven't you metioned the default should be applied to all new enums? Personally I'd say that 'closed' should be the default and the 'open' enum would require an extra keyword.<br class=""></div>
</blockquote><div class=""><br class=""></div>
<div class="">I think it should definitely be the other way round for public enums because closed is the stronger guarantee. Final is the default for classes because open is the stronger guarantee. That’s probably why we should not use the same keywords.<br class=""></div>
<div style="font-family:Arial;" class=""><br class=""></div>
<blockquote type="cite" class=""><div class=""><div class="">Now about the keyword itself. Here are two keywords that IMHO nail their behavior down to the point:<br class=""></div>
<div class=""><br class=""></div>
<div class="">finite enum A {} - so to say a closed enum (default)<br class=""></div>
<div class="">infinite enum B {} - so to say an open enum (requires default case in a switch statement)<br class=""></div>
<div class=""><br class=""></div>
<div class=""><div style="font-family:Arial;" class="">If you think the default should be the other way around, than feel free to switch that. 'finite' also implies that the enum connot ever be extended with more cases (to become infinite), which was also mentioned in your email.<br class=""></div>
<div class=""><div class=""><div style="font-family:Arial;" class=""><br class=""></div>
<div class=""><div style="font-family:helvetica, arial;font-size:13px;" class=""><div style="font-family:Arial;" class="">--&nbsp;<br class=""></div>
<div style="font-family:Arial;" class="">Adrian Zubarev<br class=""></div>
<div style="font-family:Arial;" class="">Sent with Airmail<br class=""></div>
</div>
</div><p defang_data-gmailquote="yes" style="" class=""><span class="colour" style="">Am 9. August 2017 um 00:27:53, Jordan Rose via swift-evolution (<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>) schrieb:</span><br class=""></p><blockquote type="cite" defang_data-gmailquote="yes" class=""><div style="font-family:Arial;" class=""><span class=""></span><br class=""></div>
<div style="word-wrap:break-word;line-break:after-white-space;" class=""><div class=""><br class=""></div>
<div class=""><div style="font-family:Arial;" class=""><span class=""></span><br class=""></div>
<div style="word-wrap:break-word;line-break:after-white-space;" class=""><div style="font-family:Arial;" class=""><span class="">Hi, everyone. Now that Swift 5 is starting up, I'd like to
circle back to an issue that's been around for a while: the source
compatibility of enums. Today, it's an error to switch over an enum
without handling all the cases, but this breaks down in a number of
ways: </span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">- A C enum may have "private cases" that aren't
defined inside the original enum declaration, and there's no way to
detect these in a switch without dropping down to the
rawValue.</span><br class=""></div>
<div class=""><span class="">- For the same reason, the compiler-synthesized
'init(rawValue:)' on an imported enum never produces 'nil', because
who knows how anyone's using C enums anyway?</span><br class=""></div>
<div class=""><span class="">- Adding a new case to a&nbsp;<i class="">Swift</i>&nbsp;enum in a library breaks any client code that was
trying to switch over it.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">(This list might sound familiar, and that's because
it's from a message of mine on a thread started by Matthew Johnson
back in February called "[Pitch] consistent public access
modifiers". Most of the rest of this email is going to go the same
way, because we still need to make progress here.)</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">At the same time, we really like our exhaustive
switches, especially over enums we define ourselves. And there's a
performance side to this whole thing too; if&nbsp;all cases of an
enum are known, it can be passed around much more efficiently than
if it might suddenly grow a new case containing a struct with
5000&nbsp;Strings in it.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""><b class="">Behavior</b><br class=""> <br class=""> I think there's certain behavior that is probably
not&nbsp;<i class="">terribly</i>&nbsp;controversial:<br class=""> <br class=""> - When enums are imported from Apple frameworks, they should always
require a default case, except for a few exceptions like
NSRectEdge. (It's Apple's job to handle&nbsp;this and get it right,
but if we get it wrong with an imported enum there's still the
workaround of dropping down to the raw value.)<br class=""> - When I define Swift enums in the current framework, there's
obviously no compatibility issues; we should allow exhaustive
switches.<br class=""> <br class=""> Everything else falls somewhere in the middle, both for enums
defined in Objective-C:<br class=""> <br class=""> - If I define an Objective-C enum in the current framework, should
it allow exhaustive switching, because there are no compatibility
issues, or not, because there could&nbsp;still be private cases
defined in a .m file?<br class=""> - If there's an Objective-C enum in&nbsp;<i class="">another</i>&nbsp;framework (that I built locally with Xcode,
Carthage, CocoaPods, SwiftPM, etc.), should it allow exhaustive
switching, because&nbsp;there are no&nbsp;<i class="">binary</i>&nbsp;compatibility issues, or not, because there may
be&nbsp;<i class="">source</i>&nbsp;compatibility issues? We'd
really like adding a new enum case to&nbsp;<i class="">not</i>&nbsp;be a&nbsp;breaking change even at the source
level.<br class=""> - If there's an Objective-C enum coming in through a bridging
header, should it allow exhaustive switching, because I might have
defined it myself, or not, because it&nbsp;might be non-modular
content I've used the bridging header to import?<br class=""> <br class=""> And in Swift:<br class=""> <br class=""> - If there's a Swift enum in another framework I built locally,
should it allow exhaustive switching, because there are no binary
compatibility issues, or not, because there&nbsp;may be source
compatibility issues? Again, we'd really like adding a new enum
case to&nbsp;<i class="">not</i>&nbsp;be a breaking change even at
the source level.<br class=""> </span></div>
<div class=""><span class="">Let's now flip this to the other side of the
equation. I've been talking about us disallowing exhaustive
switching, i.e. "if the enum might grow new
cases&nbsp;you&nbsp;must&nbsp;have a 'default' in a switch". In
previous (in-person) discussions&nbsp;about this feature, it's been
pointed out that the code in an otherwise-fully-covered switch is,
by definition, unreachable, and therefore untestable.
This&nbsp;also&nbsp;isn't a desirable situation to be in, but it's
mitigated somewhat by the fact that there probably aren't many
framework enums you should exhaustively switch over&nbsp;anyway.
(Think about Apple's frameworks again.) I don't have a great
answer, though.<br class=""> <br class=""> For people who like exhaustive switches, we thought about adding a
new kind of 'default'—let's call it 'unknownCase' just to be able
to talk about it. This lets&nbsp;you get warnings when you update
to a new SDK, but is even more likely to be untested code. We
didn't think this was worth the complexity.<br class=""> </span></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""><b class="">Terminology</b></span><br class=""></div>
<div class=""><span class=""><b class=""></b></span><br class=""></div>
<div class=""><span class="">The "<a href="http://jrose-apple.github.io/swift-library-evolution/" class="">Library Evolution</a>" doc (mostly written by me) originally
called these "open" and "closed" enums ("requires a default" and
"allows exhaustive switching", respectively), but this predated the
use of 'open' to describe classes and class members. Matthew's
original thread did suggest using 'open' for enums as well, but I
argued against that, for a few reasons:</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">- For classes, "open" and "non-open" restrict what
the <i class="">client</i> can do. For enums, it's more about
providing the client with additional guarantees—and "non-open" is
the one with more guarantees.</span><br class=""></div>
<div class=""><span class="">- The "safe" default is backwards: a merely-public
class can be made 'open', while an 'open' class cannot be made
non-open. Conversely, an "open" enum can be made "closed" (making
default cases unnecessary), but a "closed" enum cannot be made
"open".</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">That said, Clang now has an 'enum_extensibility'
attribute that does take 'open' or 'closed' as an argument.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">On Matthew's thread, a few other possible names came
up, though mostly only for the "closed" case:</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">- 'final': has the right meaning abstractly, but
again it behaves differently than 'final' on a class, which is a
restriction on code elsewhere in the same module.</span><br class=""></div>
<div class=""><span class="">- 'locked': reasonable, but not a standard term, and
could get confused with the concurrency concept</span><br class=""></div>
<div class=""><span class="">- 'exhaustive': matches how we've been explaining it
(with an "exhaustive switch"), but it's not exactly the <i class="">enum</i>&nbsp;that's exhaustive, and it's a long keyword to
actually write in source.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">- 'extensible': matches the Clang attribute, but also
long</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">I don't have better names than "open" and "closed",
so I'll continue using them below even though I avoided them above.
But I would <i class="">really like to find some</i>.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""><b class="">Proposal</b></span><br class=""></div>
<div class=""><span class=""><b class=""></b></span><br class=""></div>
<div class=""><span class="">Just to have something to work off of, I propose the
following:</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">1. All enums (NS_ENUMs) imported from Objective-C are
"open" unless they are declared "non-open" in some way (likely
using the&nbsp;enum_extensibility attribute mentioned above).</span><br class=""></div>
<div class=""><span class="">2. All public Swift enums in modules compiled "with
resilience" (still to be designed) have the option to be either
"open" or "closed". This only applies to libraries not distributed
with&nbsp;an app, where binary compatibility is a
concern.<br class=""> 3. All public Swift enums in modules compiled from source have the
option to be either "open" or "closed".</span></div>
<div class=""><span class="">4. In Swift 5 mode, a public enum should be <i class="">required</i> to declare if it is "open" or "closed", so that
it's a conscious decision on the part of the library author. (I'm
assuming we'll have a "Swift 4 compatibility mode" next year that
would leave unannotated enums as "closed".)</span><br class=""></div>
<div class=""><span class="">5. None of this affects non-public enums.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">(4) is the controversial one, I expect. "Open" enums
are by far the common case in Apple's frameworks, but that may be
less true in Swift.</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class=""><b class="">Why now?</b></span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">Source compatibility was a big issue in Swift 4, and
will continue to be an important requirement going into Swift 5.
But this also has an impact on the ABI: if an enum is "closed", it
can be accessed more efficiently by a client. We don't <i class="">have</i>&nbsp;to do this before ABI stability—we could access
all enums the slow way if the library cares about binary
compatibility, and add another attribute for this distinction
later—but it would be nice™ (an easy model for developers to
understand) if "open" vs. "closed" was also the primary distinction
between "indirect access" vs. "direct access".</span><br class=""></div>
<div class=""><span class=""></span><br class=""></div>
<div class=""><span class="">I've written quite enough at this point. Looking
forward to feedback!</span><br class=""></div>
<div class=""><span class="">Jordan</span><br class=""></div>
</div>
<div style="font-family:Arial;" class=""><span class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span></div>
</div>
</div>
<div style="font-family:Arial;" class=""><span class=""></span><br class=""></div>
</blockquote></div>
</div>
</div>
</div>
</blockquote><blockquote type="cite" class=""><div class=""><div style="font-family:Arial;" class=""><span class="">_______________________________________________</span><br class=""></div>
<div style="font-family:Arial;" class=""><span class="">swift-evolution mailing list</span><br class=""></div>
<div style="font-family:Arial;" class=""><span class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a></span><br class=""></div>
<div style="font-family:Arial;" class=""><span class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br class=""></div>
</div>
</blockquote><div class=""><u class="">_______________________________________________</u><br class=""></div>
<div class="">swift-evolution mailing list<br class=""></div>
<div class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""></div>
<div class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div>
</blockquote><div style="font-family:Arial;" 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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>