<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 Sep 30, 2016, at 1:23 AM, Douglas Gregor &lt;<a href="mailto:dgregor@apple.com" class="">dgregor@apple.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 Sep 28, 2016, at 4:30 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.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=""><div class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div 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="">Is the decision on "no-overlapping-conformances” something that’s seen-as set in stone permanently, set in stone for the near future, or perhaps at least somewhat open to reconsideration at the present moment?</div></div></div></blockquote><div class=""><br class=""></div><div class="">There hasn’t been a decision per se, so it that sense it’s open to reconsideration.</div><div class=""><br class=""></div><div class="">I have a strong *personal* bias against overlapping conformances, because I feel that the amount of complexity that they introduce into the language and its implementation far outweigh any benefits. </div></div></div></blockquote><div class=""><br class=""></div><div class="">I would like a bit further clarification on what the prohibition of overlapping conformances implies.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I think I presented it poorly in the proposal, and will see if I can find a clearer exposition (for posterity, if not soon enough to aid the review).</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=""><div class=""> &nbsp;For example, consider this modification of your example in a Swift that allows for same type constraints in extensions. &nbsp;Would this be allowed? </div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Short answer: no. Longer answer below.</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=""><div class="">&nbsp;There would be two different conformances to Foo for SomeWrapper, but they would never “overlap” (i.e. both be candidates for the same concrete type).</div><div class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px;"><pre class="" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;"><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">struct</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> SomeWrapper</font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">&lt;</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">Wrapped</font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">&gt;</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> {
  </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">let</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> wrapped: Wrapped
}

</font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">protocol</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> Foo {</font><pre class="" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; box-sizing: border-box; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;"><span class="pl-k" style="color: rgb(167, 29, 93); box-sizing: border-box;">associatedtype</span><font color="#333333" class=""> Bar</font></pre><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">  </font><font color="#a71d5d" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">func bar() -&gt; Bar</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">
}

</font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">extension</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> SomeWrapper: </font><font style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="" color="#0086b3">Foo</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">where</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> Wrapped == </font><font color="#0086b3" face="Menlo" style="font-size: 14px;" class="">String</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> {
  </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">func</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> </font><font style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" color="#795da3" class="">bar() -&gt; </font><font color="#0086b3" face="Menlo" style="font-size: 14px;" class="">String</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> {
    </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">return</span><font color="#333333" style="background-color: rgb(247, 247, 247);" class=""><font face="Consolas, Liberation Mono, Menlo, Courier, monospace" size="3" class=""> </font><font face="Consolas, Liberation Mono, Menlo, Courier, monospace" class=""><span style="font-size: 14px;" class="">“</span></font><font face="Consolas, Liberation Mono, Menlo, Courier, monospace" size="3" class="">Hello"</font></font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">
  }
}

</font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">extension</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> SomeWrapper: </font><span class="pl-c1" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(0, 134, 179); box-sizing: border-box;">Foo</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">where</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> Wrapped == </font><font color="#0086b3" face="Menlo" style="font-size: 14px;" class="">Int</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> {
  </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">func</span><font style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" color="#333333" class=""> </font><font style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" color="#795da3" class="">bar()</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">-&gt;</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> </font><span class="pl-c1" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(0, 134, 179); box-sizing: border-box;">Int</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> {
    </font><span class="pl-k" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; color: rgb(167, 29, 93); box-sizing: border-box;">return</span><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class=""> 0</font><font color="#333333" style="background-color: rgb(247, 247, 247); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px;" class="">
  }
}</font></pre></div></div></div></div></div></div></div></div></div></div></blockquote><div class="">This is a case where we *could* determine that the two conformances will never overlap, because we can statically determine that trying to satisfy the requirements of both extensions at the same time results in a conflict—Wrapped cannot be both equal to an Int and a String. However, I think it’s a bad idea to allow these two conformances, for a couple of reasons:</div><div class=""><br class=""></div><div class="">(1) It’s going to immediately feature-creep as developers want to be able to treat more kinds of extensions as non-overlapping, e.g., calling two protocols mutually-exclusive (Russ’s example), or introducing some kind of negative constraint (‘Wrapper: !Foo’) to arbitrarily break overlaps.&nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>Sure, we probably would see requests like this. &nbsp;The fundamental issue here IMO is that type systems are great until they don’t let you express something that is relatively obvious conceptually, such as the above example. &nbsp;This if ok as long as there is an alternative available that isn’t clearly worse (as in more boilerplate-y, less expressive, etc) and it is easily assimilated by the community using the language. &nbsp;But it becomes very frustrating when that isn’t the case. &nbsp;I’m not sure how often we will fall into the latter bucket because of this restriction but it seems likely to happen from time to time.</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=""><div class="">(2) The issues I mentioned to Russ about the type checker having to treat these as disjunctions, which can lead us into yet more exponential behavior.</div></div></div></div></blockquote><div><br class=""></div><div>Does Dave’s idea of not treating SomeWrapper itself as a type help at all here? &nbsp;That is how I also conceptualize things. &nbsp;SomeWrapper is a “type constructor” and SomeWrapper&lt;MyConcreteType&gt; is a type.</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=""><div class="">(3) I don’t think it’s good design; if you’re going to write an extension to make type X conform to protocol P, you should do so in the most general way that is reasonable for X and P—not pick the one-off case you need this moment. This way, when you do hit two ways in which X conforms to P, the compile complains and nudges you to factor the conformance into something more reusable and non-overlapping.</div></div></div></div></blockquote><div><br class=""></div><div>I agree with this in principle. &nbsp;However, sometimes a more performant implementation might be possible with more type information (as discussed below). &nbsp;It may also be the case that sometimes the general implementation is more difficult to write than is worth it for the current application.</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=""><div class=""><br class=""></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=""><div class="">Secondarily, I understand the reason for letting the “least specific” candidate conformance win (it is the most general). &nbsp;But I wonder if this might leave performance on the table in some cases where a more specific implementation could use knowledge of the more specific details to implement the members more efficiently. &nbsp;Using the example in your proposal, what if knowing `T` conforms to `S`, not just `R` allows `X5` to provide a more efficient implementation of the members of `P` and `R`? &nbsp;If so, it seems unfortunate to leave that performance on the table. &nbsp;Is this a valid concern? &nbsp;Or is it unlikely to come up often enough in practice to matter?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">It’s a valid concern, and I’m sure it does come up in practice. Let’s create a small, self-contained example:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">protocol P {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; func f()</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">protocol Q: P { }</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">struct X&lt;T&gt; { let t: T}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">extension X: P where T: P {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; func f() {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; /* general but slow */</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">extension X where T: Q {</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; func f() {</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; /* fast because it takes advantage of T: Q */</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; }</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">struct IsQ : Q { }</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">func generic&lt;U: P&gt;(_ value: u) {</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; value.f()</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">generic(X&lt;IsQ&gt;())</font></div></div></div></blockquote><div class=""><div class=""><div class=""><br class=""></div><div class="">We’d like for the call to “value.f()” to get the fast version of f() from the second extension, but the proposal doesn’t do that: the conformance to P is “locked in” to the first extension.</div><div class=""><br class=""></div><div class="">If we assume that we can see all of the potential implementations of “f” to which we might want to dispatch, we could implement some dynamic scheme that tries to pick the most specialized one. Of course, as with overlapping conformances in general, this selection process could result in ambiguities.</div></div></div></div></div></blockquote><br class=""></div><div>This is what I suspected. &nbsp;I’ll defer to Dave A on how big a concern this is, but it seems to me like a bit of a slippery slope towards sub-optimal performance.</div><div class=""><br class=""></div><div class="">Matthew</div></body></html>