<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 22, 2017, at 3:34 AM, Niels Andriesse &lt;<a href="mailto:andriesseniels@gmail.com" class="">andriesseniels@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">I agree with Joe that it's not always useful for enum cases to have independent type identity, and that it would probably also mean quite a bit of overhead if it were implemented.</div><div class=""><br class=""></div><div class="">That said, the main focus of my original proposal was to simplify enum handling (specifically, to make it syntactically more similar to the handling of other types).</div><div class=""><br class=""></div><div class="">If we do away with the idea of making enum cases subtypes of the enum for now, and implement something like the syntax below, that might still beat the current "if case" syntax and make enum handling simpler.</div><div class=""><br class=""></div><div class=""><font face="monospace, monospace" class="">enum Foo {</font></div><div class=""><font face="monospace, monospace" class="">&nbsp; case a(name: String)</font></div><div class=""><font face="monospace, monospace" class="">}</font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">foo isCase .a(name:)</font></div><div class=""><font face="monospace, monospace" class="">if let a = foo asCase? .a(name:) { print(<a href="http://a.name/" class="">a.name</a>) } // .a(name:) is not a problem because it's not a type name</font></div><div class=""><br class="">Note that we're binding to the associated value of the enum case and that the enum case is not a subtype of the enum.<br class=""><br class="">You could argue that it's syntactic sugar, but it might improve enum handling without adding too much overhead.</div></div></div></blockquote><div><br class=""></div><div>I agree that we don’t always need a subtype. &nbsp;In my example `Bar.bar` and `Foo.Nested.&nbsp;aCaseWithoutAnIndependentType` don’t have an explicit type and therefor there is not a subtype relationship. &nbsp;The other cases in the example show various ways of forming subtype relationships where that is desired.</div><div><br class=""></div><div>You’re allowing what is in many respects a downcast to something that behaves like a struct or tuple. &nbsp;What type does it have? &nbsp;Is it a tuple? &nbsp;So asCase? is a special cast operator for downcasting an enum to a “case tuple”?</div><div><br class=""></div><div>The only difference between this and real subtyping that would work with `as?` is that you don’t have implicit conversion from a subtype to the enum type. &nbsp;I can definitely see how this downcast only behavior could be useful in some cases and can’t imagine it every being harmful the way that implicit conversion to the enum could be in some cases.</div><div><br class=""></div><div>I view this type-less downcast to be potentially useful syntactic sugar but it doesn’t provide any real capabilities that we don’t already have. &nbsp;For this reason I would consider it out of scope for Swift 4. &nbsp;Real subtyping on the other hand offers very powerful new capabilities. &nbsp;It isn’t clear to me whether or not the core team views this as something they are willing to consider for Swift 4 or not, but it is definitely not in the realm of syntactic sugar so it has a better chance than `asCase?`. &nbsp;Joe, any thoughts on whether it’s worth investing time into a proposal or not?</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Feb 22, 2017 at 7:50 AM, Matthew Johnson via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Feb 21, 2017, at 2:35 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank" class="">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br class="m_4697266512448193216Apple-interchange-newline"><div class=""><div dir="ltr" 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" class="">On Tue, Feb 21, 2017 at 6:56 AM, Matthew Johnson via swift-evolution<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span><span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-<wbr class="">evolution@swift.org</a>&gt;</span><span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>wrote:<br class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="auto" class=""><div class=""><br class=""><br class="">Sent from my iPad</div><span class=""><div class=""><br class="">On Feb 21, 2017, at 2:47 AM, Patrick Pijnappel &lt;<a href="mailto:patrickpijnappel@gmail.com" target="_blank" class="">patrickpijnappel@gmail.com</a>&gt; wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class="">Just to clarify, the proposal doesn't suggest to allow the associated value to be used as a subtype of the enum.</div></div></blockquote><div class=""><br class=""></div></span><div class="">Understood.&nbsp; But it's also very desirable to have the type of the associated value be a subtype of the enum in some cases, as we already have with Optional today.</div></div></blockquote><div class=""><br class=""></div><div class="">FWIW, I agree with you here that I'd find it more useful to have the _type of the associated value_ be a subtype of the enum than to have the case itself be an independent type that is a subtype of the enum.</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">There are cases where both of these are valuable, but I agree with you - if I had to pick one I would pick the type of the associated value for sure.</div><span class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" 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" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><div class="">With respect to the latter, Swift 3 actually lowercased enum cases on the premise that they should *not* be treated as independent types. To reverse direction now (as others have mentioned in threads on other topics) partly calls into question the evolution process itself; a consensus of the community and core team has already been declared.</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">In my value subtyping manifesto I suggested allowing them to have synthesized structs backing them when they are treated as independent types by assigning the type a name that is independent of the case name.&nbsp; Cases with a single associated value may have a type that matches the type of the associated value, and may even be anonymous.&nbsp; I also allowed sub enums to be declared which are also subtypes of the enum itself.</div><div class=""><br class=""></div><div class="">Enum Bar {</div><div class="">&nbsp; &nbsp; case bar</div><div class="">}</div><div class="">enum Foo {</div><div class="">&nbsp; &nbsp;case one -&gt; struct One</div><div class="">&nbsp; &nbsp;case two(name: String) -&gt; struct Two</div><div class="">&nbsp; &nbsp;case three(Int) -&gt; Int</div><div class="">&nbsp; &nbsp;case -&gt; String</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;cases Bar // makes Bar a subtype of Foo and exposes the cases directly on Foo</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp;cases enum Nested { // this is like any other nested enum, but is also a subtype of Foo and the cases are directly available on Foo</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;case aCaseWithoutAnIndependentType</div><div class="">&nbsp; &nbsp;}</div><div class="">}</div><div class=""><br class=""></div><div class="">This is the kind of system I would like to see for enum subtypes.&nbsp; If it has a chance of being accepted for Swift 4 I would be very happy to write a proposal.&nbsp; Can anyone from the core team comment on whether enum subtypes might be in scope?</div><div class=""><div class="h5"><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" 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" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="auto" class=""><div class="">Result.success is a good example of when we would want this for the same reason it is valuable in Optional.some.</div><div class=""><br class=""></div><div class="">I would also like to see nested enums that are subtypes of the parent enum.</div><div class=""><br class=""></div><div class="">Inline:</div><div class=""><br class=""></div><div class="">enum Foo {</div><div class="">&nbsp; &nbsp;sub enum Bar {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;case one</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;case two</div><div class="">&nbsp; &nbsp;}</div><div class="">&nbsp; &nbsp;case three</div><div class="">}</div><div class=""><br class=""></div><div class="">And also wrapping an external enum:</div><div class=""><br class=""></div><div class=""><div class=""><span style="background-color:rgba(255,255,255,0)" class="">enum Bar {</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp; &nbsp; &nbsp; &nbsp;case one</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp; &nbsp; &nbsp; &nbsp;case two</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp;</span><span style="background-color:rgba(255,255,255,0)" class="">}</span></div></div><div class=""><div class=""><span style="background-color:rgba(255,255,255,0)" class="">enum Foo {</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp; &nbsp;&nbsp;// this syntax is ambiguous - we need a way to differentiate an inline sub enum from wrapping an existing enum</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp; &nbsp;sub enum Bar</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">&nbsp; &nbsp;case three</span></div><div class=""><span style="background-color:rgba(255,255,255,0)" class="">}</span></div></div><div class=""><div class="m_4697266512448193216h5"><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class=""><font face="monospace, monospace" class="">enum Result&lt;T&gt; { case .success(T), .error(Error) }</font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">func foo(_ x: Result&lt;Int&gt;) { /* ... */ }</font></div><div class=""><font face="monospace, monospace" class="">func bar(_ x: Result&lt;Int&gt;.success) { /* ... */ }<br class=""></font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">// Not this:</font></div><div class=""><font face="monospace, monospace" class="">foo(5)</font></div><div class=""><font face="monospace, monospace" class="">bar(5)</font></div><div class=""><font face="monospace, monospace" class="">// But rather:</font></div><div class=""><font face="monospace, monospace" class="">foo(.success(5))</font></div><div class=""><font face="monospace, monospace" class="">bar(.success(5))</font></div><div class=""><br class=""></div><div class="">Effectively, Result&lt;T&gt;.success would behave like a struct that is a subtype of Result&lt;T&gt;.</div><div class=""><br class=""></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Tue, Feb 21, 2017 at 12:50 PM, Joe Groff via swift-evolution<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span><span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-<wbr class="">evolution@swift.org</a>&gt;</span><span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>wrote:<br class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><br class=""><div class=""><div class=""><div class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545h5"><blockquote type="cite" class=""><div class="">On Feb 20, 2017, at 1:53 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline"><div class=""><blockquote type="cite" 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" class=""><div class=""><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline">On Feb 20, 2017, at 3:22 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" target="_blank" class="">jgroff@apple.com</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-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" class=""><blockquote type="cite" class=""><div class=""><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline">On Feb 20, 2017, at 1:04 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" target="_blank" class="">matthew@anandabits.com</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline"><div class=""><blockquote type="cite" 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" class=""><div class=""><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline">On Feb 20, 2017, at 2:38 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" target="_blank" class="">jgroff@apple.com</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-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" class=""><blockquote type="cite" class=""><div class=""><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline">On Feb 20, 2017, at 7:32 AM, Matthew Johnson via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-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" class=""><blockquote type="cite" class=""><div class=""><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline">On Feb 20, 2017, at 12:40 AM, Niels Andriesse via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">I'd like to discuss the possibility of treating the cases of a given enum as if they are subtypes of that enum. This seems like a natural thing to do because enum cases (especially when they have associated values) effectively define a closed set of subtypes.</div><div class=""><br class=""></div><div class="">Doing so would allow for constructions such as the following:</div><div class=""><br class=""></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">enum Foo {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><span style="white-space:pre-wrap" class="">&nbsp; </span>case a(name: String)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><br class=""></font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">func isA(foo: Foo) -&gt; Bool {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>// The old way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>if case .a = foo { return true }</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>return false</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>// The new way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>return foo is .a</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><br class=""></font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">func printNameIfFooIsA(foo: Foo) -&gt; Bool {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>// The old way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>if case let .a(name) = foo {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp; &nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>print(name)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>// The new way (1):</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>if let a = foo as? .a {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp; &nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>print(<a href="http://a.name/" target="_blank" class="">a.name</a>)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>// The new way (2):</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>if let name = (foo as? .a)?.name {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp; &nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>print(name)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">&nbsp;<span class="m_4697266512448193216Apple-converted-space">&nbsp;</span>}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><br class=""></div><div class="">Treating an enum's cases as its subtypes would make enums easier to work with because handling them would be syntactically the same as handling other types.</div><div class=""><br class=""></div><div class="">The pattern matching capabilities of enums wouldn't be affected by this proposal.</div><div class=""><br class=""></div><div class="">Multiple other proposals have already attempted to simplify enum handling (they have particularly focused on getting rid of "if case" and adding the ability to treat enum case tests as expressions), but none of the solutions presented in those proposals have worked out so far.</div><div class=""><br class=""></div><div class="">I believe that this could be the right solution to multiple enum-related problems that have been brought up repeatedly.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I would like to see enum cases treated as subtypes of the enum type.&nbsp; This is an interesting way to refer to the type of a case.&nbsp; Unfortunately I don’t think it will work if we accept the proposal to give cases a compound name.&nbsp; If we do that the name of this case becomes `a(name:)` which is not a valid type name.</div></div></div></blockquote><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" class="">I think there are definitely places where having cases be a subtype of an enum make sense, but I don't think it makes sense for *all* cases to be subtypes. For example, with "biased" containers like Optional and Result, it makes sense for the "right" side to be a subtype and the "wrong" side to be explicitly constructed, IMO.&nbsp; If the types of cases overlap, it would also be *ambiguous* which case ought to be constructed when the payload is converted to the enum type</div></div></blockquote><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" 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" class="">Identical case types would definitely be a problem but I don’t think overlapping case types are always a problem.&nbsp; I imagine this conversion working the same as any other ordinary overload resolution for ad-hoc overloads.</div></div></blockquote><div class=""><br class=""></div><div class="">Conversions happen at runtime too. `0 as Any as? Either&lt;Int, Int&gt;` wouldn't have any way to tell what `Either` to form if both arms of the Either were subtype candidates. An Either&lt;T, U&gt; in &lt;T, U&gt; context can end up being bound to Either&lt;Int, Int&gt; at runtime and interacting with runtime casts that way.</div></div></div></blockquote><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" 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" class="">Hmm.&nbsp; This is unfortunate.</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" 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" class="">In cases where T and U overlap and form a linear hierarchy but are not identical couldn’t the runtime determine the most direct path and choose that?</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" 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" class="">If the compiler prohibited cases with exactly the same types like `Either&lt;Int, Int&gt;` from being expressed statically how do these types end up getting formed dynamically?&nbsp; Is there any way those operations could be failable?</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" class=""><br class=""></div><br 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" class=""><blockquote type="cite" 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" class=""><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" class=""><br class=""><blockquote type="cite" class=""><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" class=""><br class=""></div><blockquote type="cite" 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" class=""><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" class="">—remember that enums are sums, not unions, and that's important for composability and uniform behavior with generics.<span class="m_4697266512448193216m_5179801444238676229m_-5758775723457976545m_-7962314986248442653Apple-converted-space">&nbsp;</span></div></div></blockquote><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" 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" class="">I’ve always thought of enums as nominal discriminated unions.&nbsp; Maybe I’m using the wrong terminology.&nbsp; Can you elaborate on the difference between sums and unions?&nbsp; When you say union are you talking about the kind of thing some people have brought up in the past where any members in common are automatically made available on the union type?</div></div></blockquote><div class=""><br class=""></div><div class="">Sums maintain structure whereas unions collapse it. As a sum, Optional&lt;T&gt; maintains its shape even when T = Optional&lt;U&gt;. If it were a union, T u Nil u Nil would collapse to T u Nil, losing the distinction between the inner and outer nil and leading to problems in APIs that use the outer nil to communicate meaning about some outer structure, such as asking for the `first` element of a collection of Optionals.</div></div></div></blockquote><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" 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" class="">Got it.&nbsp; This is certainly a problem for `Optional`.</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" 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" class="">But sometimes this behavior of collapsing the syntactic specification to a canonical sum type would be very useful.&nbsp; What is the reason we can’t have something syntactic type expressions like `Int | String`, `Int | String | String, `String | Int | String | Int`, etc all collapse to the same canonical structural sum type:</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" 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" class="">enum {</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" class="">&nbsp; &nbsp;sub case int(Int), string(String)</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" 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" 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" class="">This is how I’ve been thinking about those syntactic types.&nbsp; We already allow existential types to be formed using syntax that collapses to a canonical type:</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" 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" class="">typealias Existential1 = Protocol1 &amp; Protocol2</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" class="">typealias Existential2 = Protocol2 &amp; Existential1 &amp; Protocol 3 &amp; Protocol1</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" class="">typealias Existential3 = Existential1 &amp; Protocol3</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" 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" class="">In this example Existential1 and Existential3 are different names for the same type.</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" 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" class="">Is there a reason we can’t have similar syntax that collapses to a similarly canonical sum type?&nbsp; If we’re going to allow case subtypes this feels to me like a very natural and useful direction.&nbsp;</div></div></blockquote><div class=""><br class=""></div></div></div><div class="">A couple reasons that come to mind:</div><div class=""><br class=""></div><div class="">- Most directly, we don't allow abstraction over generic constraints. `ExistentialN&lt;T, U&gt; = T &amp; U` isn't allowed. As soon as you have abstraction over either unions or intersections, type checking becomes an unbounded search problem in the worst case, since every T binding is potentially equivalent to a T1 &amp; T2 or T1 | T2 with T1 == T2 == T.</div><div class=""><br class=""></div><div class="">- Sums and unions both imply a matching branch structure in the code somewhere to handle both possibilities. If the number of actual possibilities is different in different situations, that's a source of bugs, such as the overloading of `nil` I mentioned previously. Even if you did allow generic T &amp; T types, the worst result of someone seeing that as T1 &amp; T2 is that the operations enabled through conforming to T1 and T2 map to the same conformance.</div><div class=""><br class=""></div><div class="">-Joe</div><span class=""><br class=""><blockquote type="cite" class=""><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" 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" class="">If we don’t allow it there are two problems: people have to invent a largely meaningless name for the enum and it is incompatible with any other similarly structured enum.&nbsp; Neither is a significant problem but they do add (seemingly) unnecessary friction to the language.</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" 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" class="">I wouldn’t expect these to be widely used - they would play a similar role as tuples - but they would be very appreciated where they are used.</div><br 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" class=""><blockquote type="cite" 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" class=""><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" class=""><br class=""></div><span 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;float:none;display:inline!important" class="">-Joe</span></div></blockquote></div></blockquote></span></div><br class=""></div><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailma<wbr class="">n/listinfo/swift-evolution</a><br class=""><br class=""></blockquote></div><br class=""></div></div></div></blockquote></div></div></div><br class="">______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailma<wbr class="">n/listinfo/swift-evolution</a></blockquote></div></div></div></div></blockquote></div></div></div><br class=""></div><br class="">______________________________<wbr 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" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="">
<br class=""></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></body></html>