<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 Dec 21, 2017, at 2:06 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@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; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2017, at 2:41 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.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; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2017, at 1:26 PM, John McCall 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=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Dec 21, 2017, at 2:03 PM, Jordan Rose 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=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class="Apple-interchange-newline"><br class=""><blockquote type="cite" class=""><div class="">On Dec 20, 2017, at 12:35, Karl Wagner &lt;<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On 20. Dec 2017, at 19:54, 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 20, 2017, at 05:36, Karl Wagner 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On 19. Dec 2017, at 23:58, Ted Kremenek 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><p class="" style="-webkit-print-color-adjust: exact; margin-right: 0px; margin-bottom: 15px; margin-left: 0px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255); margin-top: 0px !important;">The review of "SE 0192 - Non-Exhaustive Enums" begins now and runs through&nbsp;<strong class="" style="-webkit-print-color-adjust: exact;">January 3, 2018</strong>.</p><p class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);">The proposal is available here:</p><blockquote class="" style="-webkit-print-color-adjust: exact; margin: 15px 0px; border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); font-family: Helvetica, arial, sans-serif; background-color: rgb(255, 255, 255);"><div class="" style="-webkit-print-color-adjust: exact; margin: 0px;"><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md</a></div></blockquote></div></div></blockquote><div class="">+1, it needs to happen (and ASAP, since it _will_ introduce source-breaking changes one way or the other).</div><div class=""><br class=""></div><div class="">I think non-exhaustive is the correct default. However, does this not mean that, by default, enums will be boxed because the receiver doesn’t know their potential size?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">It's not always boxing, but yes, there will be more indirection if the<span class="Apple-converted-space">&nbsp;</span><i class="">compiler</i>&nbsp;can't see the contents of the enum. (More on that below.)</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><div class="">That would mean that the best transition path for multi-module Apps would be to make your enums @exhaustive, rather than adding “default” statements (which is unfortunate, because I imagine when this change hits, the way you’ll notice will be complaints about missing “default” statements).</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Yep, that's going to be the recommendation. The current minimal-for-review implementation does not do this but I'd like to figure out how to improve that; at the very least it might be a sensible thing to do in the migrator.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><div class=""><br class=""></div><div class="">I do have some thoughts about how we could ease the transition (for this and other resilience-related changes), but it’s best to leave that to a separate discussion.</div><div class=""><br class=""></div><div class="">The one thing I’m still not overly fond of is the name - I would like us to keep the set of resilience/optimisation related keywords to a minimum. “exhaustive” for enums feels an awful lot like “fixed_contents” for structs - couldn’t we come up with a single name which could be used for both? I don’t think anybody’s going to want to use “exhaustive” for structs.</div></div></div></div></blockquote><br class=""></div><div class="">The core team was very focused on this too, but I contend that "exhaustive" is not about optimization and really isn't even about "resilience" (i.e. the ability to evolve a library's API while preserving binary compatibility). It's a semantic feature of an enum, much like 'open' or 'final' is for classes, and it affects what a client can or can't do with an enum. For libaries compiled from source, it won't affect performance at all—the<span class="Apple-converted-space">&nbsp;</span><i class="">compiler</i>&nbsp;still knows the full set of cases in the<span class="Apple-converted-space">&nbsp;</span><i class="">current</i>&nbsp;version of the library&nbsp;even if the programmer is forced to consider future versions.</div><div class=""><br class=""></div><div class="">I'm working on the fixed-contents proposal now, though it won't be ready for a while, and the same thing applies there: for structs compiled from source, the compiler can still do all the same optimizations. It's only when the library has binary compatibility concerns that we need to use extra indirection, and then "fixed-contents" becomes important. (As currently designed, it doesn't affect what clients can do with the struct at all.) This means that I don't expect a "normal" package author to write "fixed-contents" at all (however it ends up being spelled), whereas "exhaustive" is a fairly normal thing to consider whenever you make an enum public.</div><div class=""><br class=""></div><div class="">I hope that convinces you that "fixed-contents" and "exhaustive" don't need to have the same name. I don't think anyone loves the<span class="Apple-converted-space">&nbsp;</span><i class="">particular</i>&nbsp;name "exhaustive", but as you see in the "Alternatives considered" we didn't manage to come up with anything significantly better. If reviewers all prefer something else we'd consider changing it.</div><div class=""><br class=""></div><div class="">Thanks for responding!</div><div class="">Jordan</div><br class=""></div></div></blockquote><br class=""></div><div class="">When you say “libraries compiled from source”, what do you mean?</div></div></div></blockquote><div class=""><br class=""></div><div class="">- Other targets in your project</div><div class="">- Source packages built through SwiftPM / CocoaPods / Carthage / other</div><div class=""><br class=""></div><div class="">And I was being imprecise with the terminology, but also</div><div class=""><br class=""></div><div class="">- Libraries built by someone else but designed to be embedded into an app, so that there's no chance of a different version showing up at run-time.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><br class=""></div><div class="">As for whether its a resilience feature: actually it is completely a resilience feature. The effects on switching are only side-effects; really what “exhaustive” or “nonexhaustive” are saying is literally that cases may be added later. Even if we added private cases, you wouldn’t need to mark those enums as specially exhaustive or not; that would be implied. It’s an accommodation for things which don’t exist yet, so really, it is all about resilience IMO.</div></div></div></blockquote><div class=""><br class=""></div><div class="">"Resilience", as an admittedly fuzzily-defined term in the Swift project,&nbsp;<a href="https://github.com/apple/swift/blob/master/docs/Lexicon.rst" class="">specifically refers to what changes can be made without breaking binary compatibility</a>. It does not refer to<span class="Apple-converted-space">&nbsp;</span><i class="">every</i>&nbsp;change you can make to a library. (For comparison, adding a field to a struct is not source-breaking in Swift. We would like to make it not ABI-breaking either; that proposal's coming soon.)</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><br class=""></div><div class="">Anyway, as I see it, library authors in general ought to be happy about this:</div><div class="">+ Their libraries become safer by default, so they can make changes in the future without having to worry about breakage</div><div class="">+ It doesn’t affect your code inside of a module, so it only affects types they already explicitly marked “public”</div></div></div></blockquote><div class=""><br class=""></div><div class="">That's the intent.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><br class=""></div><div class="">The only people who lose are multi-module App developers, because they are “library authors” who don’t need to care about evolution, and now need to add attributes to things they wouldn’t have to before, or suffer language and performance penalties. Their libraries become less reusable and not resilient-by-default.</div><div class=""><br class=""></div><div class="">For example, I have an App for which I wrote a cross-platform model framework in Swift. When I compile it as a framework inside my App, it is bundled there forever. However, I use the same code to build libraries for Linux, which I would like to ship in binary form to 3rd-parties. Am I supposed to litter my code with annotations to mark those types as final, just to make the App fast and convenient to code? What happens when I need to fix a bug and distribute an updated copy, this means the 3rd-parties need to recompile (which they won’t do…).</div><div class=""><br class=""></div><div class="">Typically, for such a problem, I would recommend using a static library instead. But we don’t have those, and anyway they’re not always the best thing these days. So that’s why I started a new thread about creating a “@static” import, so App developers can go back to all the conveniences they had before.</div></div></div></blockquote><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">There won't be a perf penalty, but yes, I do expect multi-module apps to use 'exhaustive' on most of their enums, because they don't need the futureproofing. Maybe this should have been mentioned more explicitly in the proposal.</div></div></blockquote><div class=""><br class=""></div>As a perhaps more long-term design note, I think modules ought to have the ability to version-lock themselves to one or more of their dependencies. &nbsp;They would still be required to obey access control as if they were outside those dependencies, but we would suppress some of the<span class="Apple-converted-space">&nbsp;</span><i class="">semantic</i><span class="Apple-converted-space">&nbsp;</span>consequences of being outside the module, such as the need to assume non-exhaustiveness by default.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">That is, there would be two independent axes of library dependency: source vs. binary and version-compatible vs. version-locked:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; - a source dependency allows the compiler to take advantage of the implementation of public entities when generating code</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">&nbsp; - a version-locked dependency allows the compiler to take advantage of the implementation of public entities when enforcing semantics</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Apps would generally elect to primarily use version-locked source dependencies because they're just pulling down source libraries (e.g. from github) and are comfortable with updating their code if the library changes.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Source libraries on github would generally want to use version-compatible source dependencies because version-locking would put their clients in "library hell" if the locking didn't all agree.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Binary dependencies could reasonably use either.</div></div></blockquote><div class=""><br class=""></div><div class="">This model aligns pretty well with what I would like to see. &nbsp;It prevents us from paying a penalty when we don’t need the benefits provided by a restriction. &nbsp;</div><div class=""><br class=""></div><div class="">Relating this back to the current proposal, would you expect an app to have the ability to switch over an enum provided by a version-locked dependency that&nbsp;<i class="">is not</i>&nbsp;annotated with @exhaustive without requiring a default clause?</div></div></div></div></blockquote><div class=""><br class=""></div>Yes, and as we find other places where program semantics depend on knowing the implementation, I would expect them to follow suit.</div><div class=""><br class=""></div><div class="">My guess is that enum exhaustiveness is probably more prominent than any other such feature, and maybe even more prominent than all of them put together, but possible examples include:</div><div class="">&nbsp; - automatically deriving protocol conformances, which we hope will eventually be something you can do for an arbitrary protocol</div><div class="">&nbsp; - any other kind of structural metaprogramming we might add</div><div class="">&nbsp; - maybe memberwise struct initialization if there are no explicit initializers, although this is arguably an access control question (just as public/open is)</div><div class="">&nbsp; - ownership-related features that might make sense to restrict to stored properties, like expecting a struct property to have a stable address, or destructuring a struct with pattern-matching</div><div class=""><br class=""></div><div class="">Now, some of these things might be nice to allow even for resilient types. &nbsp;I know Joe has suggested adding some way of resiliently describing a structural decomposition of a type, which you could then use to derive conformances, etc. &nbsp;But since the basic motivation for restricting any of them is source/binary compatibility, and since version-locking would tell us that the programmer doesn't care about that, it seems sensible that version-locking ought to suppress the restrictions.</div><div class=""><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">Relating to @inlinable proposal also under review, would everything in a source dependency be automatically inlinable whether they were annotated as such or not (at least when version-locked)?</div></div></div></blockquote><div class=""><br class=""></div></div>Yes, and regardless of being version-locked. &nbsp;Inlining isn't semantically visible: it's <i class="">observable</i> in various low-level ways, but it's not supposed to affect basic program semantics except in incidental ways, e.g. by lowering the memory requirements so that programs start working that didn't before. &nbsp;So the compiler is generally always allowed to inline when the call is direct and the callee has a known implementation; that's just standard "as if" behavior. &nbsp;The fact that we can't do this today is just an unfortunate consequence of our current build model.</div></div></blockquote><div><br class=""></div><div>This is all exciting to hear (as a long term direction)! &nbsp;Thank you for the elaboration.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">John.</div></div></div></blockquote></div><br class=""></body></html>