<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 Aug 10, 2017, at 9:25 AM, Vladimir.S <<a href="mailto:svabox@gmail.com" class="">svabox@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">On 10.08.2017 16:46, Matthew Johnson via swift-evolution wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">On Aug 10, 2017, at 7:46 AM, James Froggatt via swift-evolution<br class=""><<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class="">Since it seems to have been lost in the noise, I want to second with support for<br class="">Xiaodi's syntax of having `default` appearing in the enum declaration itself.<br class="">It's much clearer in its intention, feels very ‘Swifty’, and more importantly it<br class="">doesn't prompt whole threads debating the semantics of `open` vs `public`.<br class=""></blockquote>I think Xiaodi’s syntax is very elegant if we want to avoid the access control<br class="">style syntax. However, it does one problem: the “error of omission” (not thinking<br class="">about open vs closed) leaves a library author with a closed enum, preventing them<br class="">from adding cases in the future without breaking compatibility. I’m not sure this<br class="">is acceptable.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Then, doesn't this mean that any 'usual' enum should be 'open' by default, and only enum declared with some marker (like 'final' or 'enum(sealed)') can be 'closed'?</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Otherwise we need to require an explicit marker for *each* enum, and so break the source compatibility? (we'll have to append that marker to each enum in your current code)</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>This is a good point. A good first decision is whether we prioritize source compatibility or the more conservative “default”. If source compatibility is prioritized Xiaodi’s proposed syntax is probably hard to beat.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Also I'd suggest this for closed enum:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">enum MyClosedEnum {</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case a</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case b</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case c</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> final</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">}</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">So, for public closed enum it will looks like:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">public enum MyClosedEnum {</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case a</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case b</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case c</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> final</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">}</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Also, if we need to explicitly mark open enum, probably we can consider 'continue' keyword, as IMO is not clear what 'default' is saying on declaration site('you must insert `default` in switch'? 'there are other `default` cases'?) :</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">public enum MyOpenEnum {</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case a</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case b</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> case c</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> continue // to be continue...</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">}</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">------------ Begin Message ------------ Group: gmane.comp.lang.swift.evolution MsgID: <<a href="mailto:CAGY80u=kVQA1q=5TMxXxFgM4tLGFUQh61EN1daepEMAA_FoE9Q@mail.gmail.com" class="">CAGY80u=kVQA1q=5TMxXxFgM4tLGFUQh61EN1daepEMAA_FoE9Q@mail.gmail.com</a>><br class="">On Tue, Aug 8, 2017 at 5:27 PM, Jordan Rose via swift-evolution < <a href="mailto:swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org" class="">swift-evolution-m3FHrko0VLzYtjvyW6yDsg@public.gmane.org</a>> wrote:<br class=""><blockquote type="cite" class="">Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to an<br class="">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:<br class="">- A C enum may have "private cases" that aren't defined inside the original<br class="">enum declaration, and there's no way to detect these in a switch without<br class="">dropping down to the rawValue. - For the same reason, the compiler-synthesized<br class="">'init(rawValue:)' on an imported enum never produces 'nil', because who knows<br class="">how anyone's using C enums anyway? - Adding a new case to a *Swift* enum in a<br class="">library breaks any client code that was trying to switch over it.<br 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]<br class="">consistent public access modifiers". Most of the rest of this email is going<br class="">to go the same way, because we still need to make progress here.)<br 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<br class="">too; if all cases of an enum are known, it can be passed around much more<br class="">efficiently than if it might suddenly grow a new case containing a struct with<br class="">5000 Strings in it.<br class="">*Behavior*<br class="">I think there's certain behavior that is probably not *terribly* controversial:<br class="">- When enums are imported from Apple frameworks, they should always require a<br class="">default case, except for a few exceptions like NSRectEdge. (It's Apple's job<br class="">to handle this and get it right, but if we get it wrong with an imported enum<br class="">there's still the workaround of dropping down to the raw value.) - When I<br class="">define Swift enums in the current framework, there's obviously no compatibility issues; we should allow exhaustive switches.<br class="">Everything else falls somewhere in the middle, both for enums defined in Objective-C:<br class="">- If I define an Objective-C enum in the current framework, should it allow<br class="">exhaustive switching, because there are no compatibility issues, or not,<br class="">because there could still be private cases defined in a .m file? - If there's<br class="">an Objective-C enum in *another* framework (that I built locally with Xcode,<br class="">Carthage, CocoaPods, SwiftPM, etc.), should it allow exhaustive switching,<br class="">because there are no *binary* compatibility issues, or not, because there may<br class="">be *source* compatibility issues? We'd really like adding a new enum case to<br class="">*not* be a breaking change even at the source level. - If there's an<br class="">Objective-C enum coming in through a bridging header, should it allow<br class="">exhaustive switching, because I might have defined it myself, or not, because<br class="">it might be non-modular content I've used the bridging header to import?<br class="">And in Swift:<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,<br class="">or not, because there may be source compatibility issues? Again, we'd really<br class="">like adding a new enum case to *not* be a breaking change even at the source<br class="">level.<br class="">Let's now flip this to the other side of the equation. I've been talking about<br class="">us disallowing exhaustive switching, i.e. "if the enum might grow new cases<br class="">you must have a 'default' in a switch". In previous (in-person) discussions<br class="">about this feature, it's been pointed out that the code in an otherwise-fully-covered switch is, by definition, unreachable, and therefore<br class="">untestable. This also isn't a desirable situation to be in, but it's mitigated<br class="">somewhat by the fact that there probably aren't many framework enums you<br class="">should exhaustively switch over anyway. (Think about Apple's frameworks<br class="">again.) I don't have a great answer, though.<br class="">For people who like exhaustive switches, we thought about adding a new kind of<br class="">'default'—let's call it 'unknownCase' just to be able to talk about it. This<br class="">lets you get warnings when you update to a new SDK, but is even more likely to<br class="">be untested code. We didn't think this was worth the complexity.<br class="">*Terminology*<br class="">The "Library Evolution <<a href="http://jrose-apple.github.io/swift-library-evolution/" class="">http://jrose-apple.github.io/swift-library-evolution/</a>>" doc (mostly written<br class="">by me) originally called these "open" and "closed" enums ("requires a default"<br class="">and "allows exhaustive switching", respectively), but this predated the use of<br class="">'open' to describe classes and class members. Matthew's original thread did<br class="">suggest using 'open' for enums as well, but I argued against that, for a few<br class="">reasons:<br class="">- For classes, "open" and "non-open" restrict what the *client* can do. For<br class="">enums, it's more about providing the client with additional guarantees—and<br class="">"non-open" is the one with more guarantees. - The "safe" default is backwards:<br class="">a merely-public class can be made 'open', while an 'open' class cannot be made<br class="">non-open. Conversely, an "open" enum can be made "closed" (making default<br class="">cases unnecessary), but a "closed" enum cannot be made "open".<br class="">That said, Clang now has an 'enum_extensibility' attribute that does take 'open' or 'closed' as an argument.<br class="">On Matthew's thread, a few other possible names came up, though mostly only<br class="">for the "closed" case:<br class="">- 'final': has the right meaning abstractly, but again it behaves differently<br class="">than 'final' on a class, which is a restriction on code elsewhere in the same<br class="">module. - 'locked': reasonable, but not a standard term, and could get<br class="">confused with the concurrency concept - 'exhaustive': matches how we've been<br class="">explaining it (with an "exhaustive switch"), but it's not exactly the *enum*<br class="">that's exhaustive, and it's a long keyword to actually write in source.<br class="">- 'extensible': matches the Clang attribute, but also long<br 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 *really like to find<br class="">some*.<br class="">*Proposal*<br class="">Just to have something to work off of, I propose the following:<br class="">1. All enums (NS_ENUMs) imported from Objective-C are "open" unless they are<br class="">declared "non-open" in some way (likely using the enum_extensibility attribute<br class="">mentioned above). 2. All public Swift enums in modules compiled "with<br class="">resilience" (still to be designed) have the option to be either "open" or<br class="">"closed". This only applies to libraries not distributed with an app, where<br class="">binary compatibility is a concern. 3. All public Swift enums in modules<br class="">compiled from source have the option to be either "open" or "closed". 4. In<br class="">Swift 5 mode, a public enum should be *required* to declare if it is "open" or<br class="">"closed", so that it's a conscious decision on the part of the library author.<br class="">(I'm assuming we'll have a "Swift 4 compatibility mode" next year that would<br class="">leave unannotated enums as "closed".) 5. None of this affects non-public<br class="">enums.<br 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.<br class="">*Why now?*<br class="">Source compatibility was a big issue in Swift 4, and will continue to be an<br class="">important requirement going into Swift 5. But this also has an impact on the<br class="">ABI: if an enum is "closed", it can be accessed more efficiently by a client.<br class="">We don't *have* to do this before ABI stability—we could access all enums the<br class="">slow way if the library cares about binary compatibility, and add another<br class="">attribute for this distinction later—but it would be nice™ (an easy model for<br class="">developers to understand) if "open" vs. "closed" was also the primary<br class="">distinction between "indirect access" vs. "direct access".<br class="">I've written quite enough at this point. Looking forward to feedback! Jordan<br class=""></blockquote>Jordan, I'm glad you're bringing this back up. I think it's clear that there's<br class="">appetite for some forward movement in this area.<br class="">With respect to syntax--which the conversation in this thread has tackled first--I agree with the discussion that "open" and "closed" are attractive but<br class="">also potentially confusing. As discussed in earlier threads, both "open" and<br class="">"closed" will constrain the enum author and/or user in ways above and beyond<br class="">"public" currently does, but the terminology does not necessarily reflect that<br class="">(as open is the antonym of closed); moreover, the implications of using these<br class="">keywords with enums don't necessarily parallel the implications of using them<br class="">with classes (for example, an open class can be subclassed; an open enum that<br class="">gains additional cases is, if anything, something of a supertype of the<br class="">original).<br class="">I'd like to suggest a different direction for syntax; I'm putting it forward<br class="">because I think the spelling itself naturally suggests a design as to which<br class="">enums are (as you call it) "open" or "closed," and how to migrate existing<br class="">enums:<br class="">``` enum MyClosedEnum { case a case b case c }<br class="">enum MyOpenEnum { case a case b case c default } ```<br class="">In words, an enum that may have future cases will "leave room" for them by using<br class="">the keyword `default`, sort of paralleling its use in a switch statement. All<br class="">existing Swift enums can therefore continue to be switched over exhaustively;<br class="">that is, this would be an additive, source-compatible change. For simplicity, we<br class="">can leave the rules consistent for non-public and public enums; or, we could<br class="">prohibit non-public enums from using the keyword `default` in the manner shown<br class="">above. Obj-C enums would be imported as though they declare `default` unless<br class="">some attribute like `enum_extensibility` is used to annotate them.<br class="">Thoughts?<br class="">------------- End Message -------------<br class="">_______________________________________________ swift-evolution mailing list <a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></blockquote>_______________________________________________ swift-evolution mailing list<span class="Apple-converted-space"> </span><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><span class="Apple-converted-space"> </span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></blockquote></div></blockquote></div><br class=""></body></html>