<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Dec 20, 2017, at 12:52, Colin Barrett &lt;<a href="mailto:colin@springsandstruts.com" class="">colin@springsandstruts.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 20, 2017, at 1:36 PM, 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="">Thanks for the links, Colin. I think neither of these approaches are appropriate for Swift, largely for the same reason: they can't be used to define a library's API. Polymorphic variants are ad-hoc union types (much like tuples are ad-hoc structs) which—apart from having other problems in Swift previously discussed on this list—means that <i class="">you can't add new cases to them</i>. That is, any API which takes `(red(r: Int) | green(g: Int) | blue(b: Int))` today can't add `alpha(a: Int)` in the future, because that would change the type. </div></div></blockquote><div class="">&nbsp;</div><div class="">It would change the type yes, but not in a binary incompatible way. Imagine this for the OS version, using OCaml pseudocode</div><div class=""><br class=""></div><div class="">type VERS = [&gt; `10_0 | `10_1 | … | `10_13 ]</div><div class=""><br class=""></div><div class="">Then, next year, you’d change VERS to be,</div><div class=""><br class=""></div><div class="">type VERS = [&gt; `10_0 | `10_1 | … | `10_13 | `10_14 ]</div><div class=""><br class=""></div><div class="">Any code that dealt with a VERS would still work, as it had to handle that it could contain other tags.</div></div></div></div></blockquote><div><br class=""></div><div>Sorry, I had this worked out in my head but then didn't put it into the email correctly! The sticking point is that Swift allows overloads by type, which means that argument types have to go into the mangled name of the function. (Another way to think of this is to say "to uniquely identify a function across releases, you must know its argument and return types as well as its full name".) That means that we can't just add a new case into the type, because it would change the function's type.</div><div><br class=""></div><div>Okay, but what if VERS were an actual new type rather than just a typealias? Well, then you have a non-exhaustive enum.</div><div><br class=""></div><div>(David Owens brought up on Twitter today that it could be a <i class="">different</i>&nbsp;kind of declaration rather than 'enum'.&nbsp;<a href="https://twitter.com/UINT_MIN/status/943896442472620032" class="">My response</a>&nbsp;was that that could work, but you end up in a worse case where (a) the two declarations are equivalent when they're not public, and (b) it's still easy to use the wrong one, especially going from Swift 1-4 habits.)</div><div><br class=""></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=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">ML-style exceptions have the opposite problem; they are <i class="">completely</i>&nbsp;unconstrained and so a <i class="">client</i>&nbsp;can add new "cases" without the library author being prepared. (Swift's error-handling model in general behaves a lot like this, except it doesn't get ML's knowledge of which errors might be thrown.)</div></div></blockquote><div class=""><br class=""></div>Yes, I was imagining that this would be for something with an OCaml type like [&gt; ] &nbsp;or TOP, which I don’t believe is a thing? My OCaml-fu is quite weak.<br class=""><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="">I'd sum this up by saying Swift is differing from ML and from most other languages because it is solving a different problem. Swift is designed such that the compiler does not <i class="">require</i>&nbsp;whole-program knowledge to produce a correct, working, type-safe program. It will use any cross-module knowledge it can for optimization purposes, but the language semantics do not depend on it. And this is critical, as you note, for libraries with binary compatibility concerns.</div></div></div></blockquote><div class=""><br class=""></div><div class="">That is… not different from ML? ML’s modules have precisely this properly, do they not? Or am I misunderstanding what you’re saying here.</div></div></div></div></blockquote><div><br class=""></div><div>ML modules provide separation of concerns, but as far as I know they can't actually be swapped out at runtime, and if someone <i class="">were</i>&nbsp;to do this they wouldn't be allowed to add a new variant to an existing datatype.</div><div><br class=""></div><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="">Thanks for the reply, it’s appreciated! Hope you’re well in California, envious of your weather trudging thru the snow here in NYC.</div></div></blockquote><br class=""></div><div>Happy holidays, Colin, and everyone else on the list. :-)</div><div><br class=""></div><div><div>Jordan</div><div class=""><br class=""></div></div><br class=""></body></html>