<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=""><blockquote type="cite" class="">On Aug 16, 2016, at 11:42 PM, Slava Pestov &lt;<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>&gt; wrote:</blockquote><blockquote type="cite" class=""><blockquote type="cite" class=""><br class=""></blockquote></blockquote><div><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=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">Argh, that’s particularly frustrating since in something like ‘func foo&lt;T : P&gt;(t: T)’ or ‘func foo&lt;S : Sequence&gt;(s: S) where S.IteratorElement: P’, you’re only ever getting instances anyway since the parameter is in the input, so calling initializers or static functions isn’t something you can even do (unless you call .dynamicType, at which point you *do* have a concrete type at runtime thanks to the dynamic check).</div></div></div></blockquote><div class=""><br class=""></div>Well, if you have ‘func foo&lt;T : P&gt;(t: T)’, then you can write T.someStaticMember() to call static members — it’s true you also have an instance ’t’, but you can also work directly with the type. But I suspect this is not what you meant, because:</div></div></blockquote><div><br class=""></div><div>Agh, you’re right, I’d forgotten about that. It’s days like this that I miss Objective-C’s “It just works” dynamism. ;-)</div><br class=""><blockquote type="cite" 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">I wish there were a way to have partial conformance in cases like these. Like how this causes what’s probably Swift’s most confusing compiler error (certainly one of its most asked about):</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">protocol</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>P:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">Equatable</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>{</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">static</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>==(l:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">Self</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, r:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">Self</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) -&gt;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Bool</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp;&nbsp; &nbsp;</span><br class="webkit-block-placeholder"></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>foo()</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">}</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures;"></span><br class=""></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">struct</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>S:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">P</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>{</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">static</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>==(l:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">S</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, r:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">S</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) -&gt;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Bool</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>{</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(187, 44, 162);"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">return</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">true</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; }</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp;&nbsp; &nbsp;</span><br class="webkit-block-placeholder"></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>foo() {</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; &nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(61, 29, 129);">print</span><span class="" style="font-variant-ligatures: no-common-ligatures;">(</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"foo"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">)</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">&nbsp; &nbsp; }</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">}</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;"><span class="" style="font-variant-ligatures: no-common-ligatures;"></span><br class=""></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">let</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>s =<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">S</span><span class="" style="font-variant-ligatures: no-common-ligatures;">()</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0);"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">let</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span>p =<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">s</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">as</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);">P</span><span class="" style="font-variant-ligatures: no-common-ligatures;"><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="font-variant-ligatures: no-common-ligatures;">// error:&nbsp;</span>Protocol ‘P’ can only be used as a generic constraint because it has Self or associated type requirements</div></div></div></div></blockquote><div class=""><br class=""></div>Yep :) So the property of ‘can be used as an existential type’ is actually a bit different from ‘protocol conforms to itself’. The rules here are:</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="">- Self must not appear in contravariant position</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="">- Protocol has no associated types</div></blockquote><div><blockquote type="cite" class=""><br class=""></blockquote></div><blockquote type="cite" 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="">Note that static members and initializers are OK, and you can call them via ‘p.dynamicType.foo()’ where p : P.</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=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">It would make using protocols so much less teeth-grinding if the compiler *did* allow you to type the variable as P, but then would just throw an error if you tried to call one of the “problem” methods (in this case, using the ‘==' operator would be an error, but calling ‘foo’ would be fine). If this were possible, the conformance for a variable typed P would just not pick up “illegal” things like initializers, and would also leave out conformance for things like 'makeIt()' above which return the generic parameter in the output, rather than the input, necessitating a concrete type. I’m probably dreaming, I know.</div></div></div></blockquote><div class=""><br class=""></div><div class="">In the type checker, this more precise, per-member check is already implemented, interestingly enough. It comes up with protocol extensions. Imagine you have a protocol ‘P’ that can be used as an existential, but an extension of P adds a problematic member:</div><div class=""><br class=""></div><div class="">protocol P {</div><div class="">&nbsp; func f() -&gt; Int</div><div class="">}</div><div class=""><br class=""></div><div class="">extension P {</div><div class="">&nbsp; func ff(other: Self) -&gt; Int { return f() + s.f()) }</div><div class="">}</div><div class=""><br class=""></div><div class="">Here, you don’t want to entirely ban the type ‘P’, because the extension might come from another module, and it shouldn’t just break everyone’s code. So the solution is that you can use ‘P’ as an existential, but if you try to reference ‘p.ff’ where p : P, you get a diagnostic, because that particular member is unavailable.</div><div class=""><br class=""></div><div class="">In fact, I think the separate restriction that rules out usage of the overall type when one of the protocol’s requirements is problematic, is mostly artificial, in that it could just be disabled and you’d be able to pass around ‘Equatable’ values, etc, because the lower layers don’t care (I think).</div><div class=""><br class=""></div><div class="">I do remember it was explained to me at one point that this is how it was in the early days of Swift, but it made code completion and diagnostics confusing, because with some protocols (like Sequence) most members became inaccessible.</div></div></blockquote><div><br class=""></div><div>Oh dear. I don’t know how confusing those things were, but if you Google the “self or associated type requirements” error to see how many people it has confused, I think you’ll find that it’d be quite hard for the more precise check to create more confusion than that. Perhaps I should write up a proposal to change this, if it’s easily enough done that it’s actually been done once already.</div><div><br class=""></div><div>Imagine if other aspects of the system worked this way, like the ObjC bridge for instance. Imagine you had an NSObject-derived class that some ObjC code somewhere was calling, and the minute you add a method somewhere that returns a tuple or something, instead of just not giving ObjC access to that one method, it suddenly just up and said BZZT. NO OBJC BRIDGE FOR YOU. Wouldn’t that be frustrating?</div><div><br class=""></div><div>The other trouble is that it’s not just confusing; it can very easily get in the way of your work even if you know exactly what’s going on, necessitating kludges like AnyHashable just to do things like have a dictionary that can take more than one key type (an example that’s particularly irritating since the only method you care about, hashValue, is just a plain old Int that doesn’t care about the Self requirement at all). I know that a while ago I ended up using my own Equatable substitute with an ObjC-style isEqual() method on some types, just because actually implementing Equatable was throwing a huge spanner into the rest of the design.</div><br class=""><blockquote type="cite" 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=""><div class="">A better approach is to implement more general existential types which expose ways of working with their associated types, rather than just banning certain members from being used altogether. This is described in Doug's ‘completing generics’ document, and again, it is quite a large project :)</div></div></blockquote><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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div></div></div></blockquote></div><blockquote type="cite" 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">Actually, what I wish is that Swift had an equivalent of the 'id &lt;P&gt;’ type in Objective-C. That notation always stood for an instance of something that conformed to P, rather than "maybe P itself, and maybe something that conforms to it”. If we could do that, we could just pass sequences of 'id &lt;P&gt;’ (in whatever syntax we gave it in Swift) to a sequence where Element: P, and it’d work fine regardless of anything that prevented P from conforming to P.</div></div></div></blockquote><div class=""><br class=""></div>In fact I think some of the proposals call for Any&lt;P&gt; as the syntax for the most general existential of type ‘P’, with other syntax when associated types are bound. I must admit I haven’t followed the discussions around generalized existentials very closely though.</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="">So it sounds like your original :== operator idea is really about implementing self-conforming protocols, as well as generalized existentials. These are quite difficult projects, but I hope we’ll tackle them one day. Patches are welcome :-)</div></blockquote><br class=""></div>Well, the idea was to create an easier-to-implement alternative to self-conforming protocols, which could be done if :== were expanded to one function that uses ==, and another with the same body that uses :, because I was under the impression that the compiler team did not want to implement self-conforming protocols.<div class=""><br class=""></div><div class="">Charles</div><div class=""><br class=""></div></body></html>