<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 Mar 2, 2016, at 8:19 PM, Joe Groff <<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>> 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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Mar 2, 2016, at 6:20 PM, David Smith via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Mar 2, 2016, at 5:22 PM, Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi all,<div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class=""><font size="4" class="">Existentials</font></b><br class=""><br class="">Existentials aren’t really generics per se, but the two systems are closely intertwined due to their mutable dependence on protocols.<br class=""><br class=""><span class="" style="font-size: 14px;"><i class="">*Generalized existentials</i></span></div><div class=""><br class=""></div><div class="">The restrictions on existential types came from an implementation limitation, but it is reasonable to allow a value of protocol type even when the protocol has Self constraints or associated types. For example, consider IteratorProtocol again and how it could be used as an existential:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><font face="Menlo" class="">protocol IteratorProtocol {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> associatedtype Element</font></div></div><div class=""><div class=""><font face="Menlo" class=""> mutating func next() -> Element?</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">let it: IteratorProtocol = …</font></div><div class=""><font face="Menlo" class="">it.next() // if this is permitted, it could return an “Any?”, i.e., the existential that wraps the actual element</font></div></blockquote><div class=""><font face="Menlo" class=""><br class=""></font></div><div class="">Additionally, it is reasonable to want to constrain the associated types of an existential, e.g., “a Sequence whose element type is String” could be expressed by putting a where clause into “protocol<…>” or “Any<…>” (per “Renaming protocol<…> to Any<…>”):</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Menlo" class="">let strings: Any<Sequence<b class=""><span class="Apple-converted-space"> </span>where .Iterator.Element == String</b>> = [“a”, “b”, “c”]</font></div></blockquote><div class=""><br class=""></div><div class="">The leading “.” indicates that we’re talking about the dynamic type, i.e., the “Self” type that’s conforming to the Sequence protocol. There’s no reason why we cannot support arbitrary “where” clauses within the “Any<…>”. This very-general syntax is a bit unwieldy, but common cases can easily be wrapped up in a generic typealias (see the section “Generic typealiases” above):</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Menlo" class="">typealias AnySequence<Element> =<span class="Apple-converted-space"> </span><b class="">Any<Sequence where .Iterator.Element == Element></b></font></div><div class=""><font face="Menlo" class="">let strings: AnySequence<String> = [“a”, “b”, “c”]</font></div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><i class="" style="font-size: 14px;">Opening existentials</i></div><div class=""><br class=""></div><div class="">Generalized existentials as described above will still have trouble with protocol requirements that involve Self or associated types in function parameters. For example, let’s try to use Equatable as an existential:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Menlo" class="">protocol Equatable {</font></div><div class=""><font face="Menlo" class=""> func ==(lhs: Self, rhs: Self) -> Bool</font></div><div class=""><font face="Menlo" class=""> func !=(lhs: Self, rhs: Self) -> Bool</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">let e1: Equatable = …</font></div><div class=""><font face="Menlo" class="">let e2: Equatable = …</font></div><div class=""><font face="Menlo" class="">if e1 == e2 { … }<span class="Apple-converted-space"> </span><i class="">//<span class="Apple-converted-space"> </span><b class="">error</b>:</i> e1 and e2 don’t necessarily have the same dynamic type</font></div></blockquote><div class=""><br class=""></div><div class="">One explicit way to allow such operations in a type-safe manner is to introduce an “open existential” operation of some sort, which extracts and gives a name to the dynamic type stored inside an existential. For example:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> </div><div class=""><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Menlo" class="">if let storedInE1 = e1 openas T { // T is a the type of storedInE1, a copy of the value stored in e1</font></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Menlo" class=""> if let storedInE2 = e2 as? T { // is e2 also a T?</font></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Menlo" class=""> if storedInE1 == storedInE2 { … } // okay: storedInT1 and storedInE2 are both of type T, which we know is Equatable</font></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Menlo" class=""> }</font></blockquote><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Menlo" class="">}</font></blockquote></div><div class=""><br class=""></div><div class="">Thoughts?</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>- Doug</div><div class=""><br class=""></div></div></div></blockquote><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Thanks for sending this out! A lot of the stuff here looks amazingly useful, and I'm excited to see it being discussed.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">The choice of Equatable as an example for opening existentials is an interesting one here, because it's one of the few cases I can think of where differing dynamic types is actually fully defined: they're not equal. In ObjC we express that by starting every -isEqual: implementation with if (![other isKindOfClass:[self class]]) { return NO; }, which while clunky and easy to forget, does neatly express the desired semantics with no burden at the callsite. </div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">My first thought for how to express that in Swift was "ok, provide an == for (Any, Any) that just always says false", but that would defeat the ability to say something just doesn't make sense to compare with ==, which is a nice feature and prevents bugs.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Next thought for expressing it cleanly was:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><span class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;">protocol Equatable {</span><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;"> func ==(lhs: Self, rhs: Self) -> Bool</span><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;"> func !=(lhs: Self, rhs: Self) -> Bool</span><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> func ==(lhs: Self, rhs: !Self) -> Bool { return false }<br class=""> func !=(lhs: Self, rhs: !Self) -> Bool { return true }<br class="">}<br class=""><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">and I guess another equivalent way of writing it that doesn't require a new syntactic construct would be:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">protocol Equatable {<br class=""> func ==(lhs: Self, rhs: Self) -> Bool<br class=""> func !=(lhs: Self, rhs: Self) -> Bool<div class=""> func ==<Other:Equatable where Other != Self>(lhs: Self, rhs: Other) -> Bool { return false }<br class=""> func !=<Other:Equatable where Other != Self>(lhs: Self, rhs: Other) -> Bool { return true }<br class="">}</div></div></div></blockquote><div class=""><br class=""></div><div class="">My thinking is that this could be expressed as extending the existential type to conform to the protocol:</div><div class=""><br class=""></div><div class="">extension Any<Equatable>: Equatable {</div><div class=""> func ==(lhs: Any<Equatable>, rhs: Any<Equatable>) -> Bool {</div><div class=""> if let lrhs = rhs as? lhs.Self {</div><div class=""> return lhs == rlhs</div><div class=""> }</div><div class=""> return false</div><div class=""> }</div><div class="">}</div></div></div></blockquote><div><br class=""></div><div>Oh wow, I did not put 2 and 2 together here and get "you can extend existentials of something without extending that thing itself". That is *so pretty*. Hesitation withdrawn!</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>David</div><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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">which would make this idea a minor extension of the "Concrete Same-Type Requirements" section.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">However, this still has a similar flaw to the first idea I had, which is that it introduces a valid == operator for things that never make sense to compare, when what we actually want is one that will only be accepted if there's insufficient information to determine whether it's valid (i.e. Equatable existentials). I suppose there's a relatively obvious syntax to express that directly:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">protocol Equatable {<br class=""> func ==(lhs: Self, rhs: Self) -> Bool<br class=""> func !=(lhs: Self, rhs: Self) -> Bool<div class=""> func ==<Other:Equatable where Other ?= Self>(lhs: Self, rhs: Other) -> Bool { return false }<br class=""> func !=<Other:Equatable where Other ?= Self>(lhs: Self, rhs: Other) -> Bool { return true }<br class="">}</div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Where "?=" would be read as "might be equal to". It's not clear to me if this sort of "default implementation for non-matching existentials" concept is applicable beyond Equatable though, and if not it seems like a lot of machinery to add for one case.</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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The "introducing an == operator for things that never make sense to compare" problem could be avoided by a type system rule that, when we bind a generic parameter from multiple value parameter, we don't upconvert to a type that neither parameter statically has. Since `==` is `<Self> (Self, Self) -> Bool`, that would prevent us from picking `Self == Any<Equatable>` if you called `Int == Float`, but would allow it if one or the other parameter was already Any<Equatable>.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; 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; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">-Joe</div></div></blockquote></div><br class=""></body></html>