> On Dec 20, 2017, at 12:52, Colin Barrett <co...@springsandstruts.com> wrote:
>> On Dec 20, 2017, at 1:36 PM, Jordan Rose <jordan_r...@apple.com 
>> <mailto:jordan_r...@apple.com>> wrote:
>> 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 you can't add new cases 
>> to them. 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.
> It would change the type yes, but not in a binary incompatible way. Imagine 
> this for the OS version, using OCaml pseudocode
> type VERS = [> `10_0 | `10_1 | … | `10_13 ]
> Then, next year, you’d change VERS to be,
> type VERS = [> `10_0 | `10_1 | … | `10_13 | `10_14 ]
> Any code that dealt with a VERS would still work, as it had to handle that it 
> could contain other tags.

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.

Okay, but what if VERS were an actual new type rather than just a typealias? 
Well, then you have a non-exhaustive enum.

(David Owens brought up on Twitter today that it could be a different kind of 
declaration rather than 'enum'. My response 
<https://twitter.com/UINT_MIN/status/943896442472620032> 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.)

>> ML-style exceptions have the opposite problem; they are completely 
>> unconstrained and so a client 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.)
> Yes, I was imagining that this would be for something with an OCaml type like 
> [> ]  or TOP, which I don’t believe is a thing? My OCaml-fu is quite weak.
>> 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 require 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.
> 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.

ML modules provide separation of concerns, but as far as I know they can't 
actually be swapped out at runtime, and if someone were to do this they 
wouldn't be allowed to add a new variant to an existing datatype.

> Thanks for the reply, it’s appreciated! Hope you’re well in California, 
> envious of your weather trudging thru the snow here in NYC.

Happy holidays, Colin, and everyone else on the list. :-)


swift-evolution mailing list

Reply via email to