<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 Feb 16, 2017, at 5:13 PM, Karl Wagner &lt;<a href="mailto:razielim@gmail.com" class="">razielim@gmail.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 17 Feb 2017, at 00:00, Karl Wagner &lt;<a href="mailto:karl.swift@springsup.com" class="">karl.swift@springsup.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 16 Feb 2017, at 23:44, Matthew Johnson 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="">I have been thinking a lot about enums and value subtyping lately and decided to write down the ideas I’ve been thinking about. &nbsp;The result is a manifesto-style document that explores a broad landscape of features that could eventually lead to proposals (at the right time, of course).<br class=""><br class="">I’m presenting this document to the list now mostly because I am not sure which of these features (if any) might be relevant to ABI stability, particularly with respect to standard library APIs. &nbsp;I do not wish to distract the list from the focus on Swift 4, phase 1. &nbsp;Let’s try not to get distracted by exciting ideas that won’t be in scope until at least phase 2. &nbsp;Feel free to send feedback off list if you’re interested in discussing ideas that may not be relevant to Swift evolution at this time.<br class=""><br class="">Because this document covers a pretty broad range of topics it might be a good idea to start a new thread before jumping in to discussion about a specific aspect of it. &nbsp;Please consider doing that if it is relevant before responding directly to this thread.<br class=""><br class="">As this is a relatively large document I am only providing a link: <a href="https://gist.github.com/anandabits/5b7f8e3836387e893e3a1197a4bf144d" class="">https://gist.github.com/anandabits/5b7f8e3836387e893e3a1197a4bf144d</a><br class=""><br class="">To whet your appetite, the topics covered include:<br class=""><br class="">* Definition of value subtyping<br class=""> &nbsp;&nbsp;* Transitivity of value subtypes<br class=""> &nbsp;&nbsp;* Generic supertype constraints<br class="">* Axiomatic value subtype relationships<br class="">* Enums: Value Subtype Relationships by definition<br class=""> &nbsp;&nbsp;* Nominal case types<br class=""> &nbsp;&nbsp;* Nominal unions<br class=""> &nbsp;&nbsp;* Generic enums and Optional<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Cases with unbound generic arguments<br class=""> &nbsp;&nbsp;* Structural Unions<br class=""> &nbsp;&nbsp;* Enum subtypes<br class=""> &nbsp;&nbsp;* Inline enum subtypes<br class=""> &nbsp;&nbsp;* Inline generic enum subtypes<br class=""> &nbsp;&nbsp;* Conditional cases (and GADTs)<br class=""> &nbsp;&nbsp;* Inline case types<br class=""> &nbsp;&nbsp;* Nominal cases with inline types<br class=""> &nbsp;&nbsp;* Case type implementation sharing<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Shared stored properties<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Subenum stored properties<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Shared methods and computed properties<br class="">* User-defined case patterns<br 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><br class=""></div></div></blockquote></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; color: rgb(51, 51, 51);" class=""><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">enum</span> <span class="pl-en" style="box-sizing: border-box; color: rgb(121, 93, 163);">IntOrString</span>: <span class="pl-e" style="box-sizing: border-box; color: rgb(121, 93, 163);"><span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">Int</span> </span>| <span class="pl-e" style="box-sizing: border-box; color: rgb(121, 93, 163);"><span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span> </span>{
  <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">case</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">Int</span>
  <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">case</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);"></span>}

<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">func</span> <span class="pl-en" style="box-sizing: border-box; color: rgb(121, 93, 163);">takesAnonymousUnion</span>(<span class="pl-smi" style="box-sizing: border-box;"><span class="pl-en" style="box-sizing: border-box; color: rgb(121, 93, 163);">intOrString</span></span>: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">Int</span> | <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>) {}</pre><div class=""><br class=""></div></div><div class=""><div class="">Haven’t been through it all, just pointing out that “Structural unions” and anonymous unions have been suggested and rejected before.</div><div class=""><br class=""></div><div class="">- Karl</div></div></div></div></blockquote><br class=""></div><div class="">(maybe I should elaborate on that, because you do point it out in the document)</div><div class=""><br class=""></div><div class="">What I mean is that the reason this was rejected before was that people should be using protocols instead, and building semantic contracts. “Int” and “String” may have a method that looks the same but behaves very differently - the union provides no guarantees about _behaviour_. Protocols *do* give you guarantees about behaviour.</div></div></div></blockquote><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="">Basically, the correct way to write this (today) is:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Courier" class="">protocol CommonIntAndStringMethods {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; func doSomething()</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">enum IntOrString {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; case integer(Int)</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; case string(String)</font></div><div class=""><font face="Courier" class="">}</font></div><div class=""><font face="Courier" class="">extension Int: CommonIntAndStringMethods {}</font></div><div class=""><font face="Courier" class="">extension String: CommonIntAndStringMethods {}</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">func myFunc(_ x: IntOrString) {</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; let val: CommonIntAndStringMethods</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; if case .integer(let i) = x &nbsp; &nbsp; { val = i }</font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; else if case .string(let s) = x { val = s }</font></div><div class=""><font face="Courier" class=""><br class=""></font></div><div class=""><font face="Courier" class="">&nbsp; &nbsp; val.doSomething()</font></div><div class=""><font face="Courier" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">What you are proposing looks superficially similar, but isn’t. We call “doSomething” on a single type, with guaranteed same semantics.</div></div></div></blockquote><div><br class=""></div><div>Thanks for pointing out this aspect of the prior discussions. &nbsp;This is great feedback. &nbsp;This part of the prior discussions had slipped my mind so I didn’t distinguish the unions I am talking about from the union types that some people have asked for in the past. &nbsp;I’ll update the manifesto to be more clear about this.</div><div><br class=""></div><div>The intent is not to expose common methods on the union type at all. &nbsp;In fact all you could do with a structural union as I am defining it is attempt to downcast (or switch with cast patterns). &nbsp;These structural unions would be for things such as:</div><div><br class=""></div><div>typealias JSONValue = None | Bool | Int | Double | String</div><div><br class=""></div><div>Sometimes what we require union types like this. &nbsp;Today we can define an enum JSONValue bit it is less elegant than it could be. &nbsp;We don’t get the subtype relationship with Bool, Int, Double, String, etc. &nbsp;This means we don’t get implicit conversion to JSONValue and we don’t have the ability to downcast from JSONValue. &nbsp;It also means that my JSONValue is incompatible with your JSONValue.</div><div><br class=""></div><div>None of this has anything to do with any operations that might be available on any (or all) of the types making up the union. &nbsp;I think this makes the implementation much more tractable and avoids the semantic issues you point out.</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="">- Karl</div><br class=""></div></div></blockquote></div><br class=""></body></html>