<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><br><br><div id="AppleMailSignature">Sent from my iPad</div><div><br>On Dec 10, 2017, at 3:41 PM, Jens Persson via swift-users <<a href="mailto:swift-users@swift.org">swift-users@swift.org</a>> wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr"><div>I'm trying to get my head around the current behavior, but its very hard to understand and remember, and judging by the comments here and on my bug report (SR-6564), so does even people in the core team. It would be nice if someone could present a complete set of rules (all the ones I've seen are far to simplified and does not cover all cases).</div><div>Here's another example to consider:</div><div><br></div><div>protocol P {</div><div> associatedtype T</div><div> func f() // *</div><div>}</div><div>extension P {</div><div> func f() { print("T is unknown") }</div><div>}</div><div>extension P where T == Int {</div><div> func f() { print("T is Int") }</div><div>}</div><div><br></div><div>struct X<T> : P {</div></div></div></blockquote><div><br></div><div>FWIW, this does not compile. You need to provide a typealias for T which you can’t do when the generic parameter is named T.</div><br><blockquote type="cite"><div><div dir="ltr"><div> func f() { print("this one is actually best") }</div><div>}</div><div>extension X where T == Int {</div><div> func f() { print("this one is actually better than best.") }</div><div>}</div><div><br></div><div>struct Y<U> where U: P, U.T == Int {</div><div> typealias T = U.T</div><div> var a: U</div><div> func g() { a.f() }</div><div>}</div><div><br></div><div>let x = X<Int>()</div><div>x.f() // What will this print?</div></div></div></blockquote><div><br></div><div>This prints “<span style="background-color: rgba(255, 255, 255, 0);">this one is actually better than best.” because the method is invoked on a concrete type. Overload resolution is used to identify the most specific implementation which in this case is the method in the concrete extension on X.</span></div><br><blockquote type="cite"><div><div dir="ltr"><div><br></div><div>let y = Y(a: X<Int>())</div><div>y.g() // What will this print?</div></div></div></blockquote><div><br></div>This prints ”<span style="background-color: rgba(255, 255, 255, 0);">this one is actually best”. This is because the method is called in a generic context and is a protocol requirement. This means it is dispatched through the protocol witness table. The methods in the extensions on P are default implementations which are disregarded because X provides its own implementation. The overload in the extension on X is not visible at all in a generic context because it does not participate in X’s conformance to P.</span><br><br><blockquote type="cite"><div><div dir="ltr"><div><br></div><div>If anyone knows for sure what this program will print (without having to run it), please enlighten me!</div></div></div></blockquote><div><br></div><div>I hope the above helps. If you have further questions please ask!</div><br><blockquote type="cite"><div><div dir="ltr"><div><br></div><div>/Jens</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Dec 9, 2017 at 1:54 AM, Jordan Rose <span dir="ltr"><<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div>Consider this example:</div><div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><span class=""><div><div>protocol P {</div></div><div><div> associatedtype T</div></div><div><div> func f() // *</div></div><div><div>}</div></div><div><div>extension P {</div></div><div><div> func f() { print("T is unknown") }</div></div><div><div>}</div></div><div><div>extension P where T == Int {</div></div><div><div> func f() { print("T is Int") }</div></div><div><div>}</div></div><div><div><br></div></div><div><div>struct X<T> : P {</div></div></span><div><div> func f() { print("this one is actually best") }</div></div><span class=""><div><div>}</div></div><div><div><br></div></div><div><div>struct Y<U> where U: P, U.T == Int {</div></div></span><span class=""><div><div> typealias T = U.T</div></div><div><div> var a: U</div></div><div><div> func g() { a.f() }</div></div><div><div>}</div></div><div><div><br></div></div></span><span class=""><div><div>let x = X<Int>()</div></div></span><div><div>x.f() // "this one is actually best"</div></div><span class=""><div><div><br></div></div><div><div>let y = Y(a: X<Int>())</div></div></span><div><div>y.g() // "this one is actually best"</div></div></blockquote><div><div><br></div></div><div>I can't think of any other choice for 'a.f()' that would preserve this behavior, which means we're doing the best thing: prefer dynamic dispatch over static dispatch when operating on a generic value. (Or at least the "least bad" thing.) And of course this reasoning has to be local; Y.g can't look and say "oh, I know nothing else conforms to P, and X {does, doesn't} have a custom implementation, so I should pick the constrained extension instead".</div><div><br></div><div>The real answer might be "we should have had a different syntax for default implementations vs. mixin operations", but that's a much bigger can of worms.</div><span class="HOEnZb"><font color="#888888"><div><br></div><div>Jordan</div></font></span><div><div class="h5"><br><div><br><blockquote type="cite"><div>On Dec 8, 2017, at 13:07, Jens Persson via swift-users <<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>> wrote:</div><br class="m_3843216022228456842Apple-interchange-newline"><div><div dir="ltr"><div>Thanks Slava and Greg,</div><div><br></div><div>(</div>I'm aware that it prints "T is Int" from both calls if I remove func f() from P itself, that's why I wrote "... <span style="font-size:12.800000190734863px">unless * is commented out." in</span> the comment of the last line<div><span style="font-size:12.800000190734863px">Note that the "U.T == Int"-part of </span><br></div><div><span style="font-size:12.800000190734863px"> struct Y<U> where U: P, U.T == Int {</span></div><div><span style="font-size:12.800000190734863px">is key here. If it had been only</span></div><div><span style="font-size:12.800000190734863px"> struct Y<U> where U: P {</span><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">then I hadn't been surprised that it printed "T is unknown".</span></div><div><span style="font-size:12.800000190734863px">)</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">Filed </span><a href="https://bugs.swift.org/browse/SR-6564" target="_blank">https://bugs.swift.org/<wbr>browse/SR-6564</a><span style="font-size:12.800000190734863px"> since I think it is just strange that the compiler should not use its knowledge of U.T == Int when choosing between the two f()-implementations.</span></div><div><span style="font-size:12.800000190734863px">I think I will be a little disappointed if the solution is to deem it an ambiguity</span></div><div><span style="font-size:12.800000190734863px">: )</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div>/Jens</div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px"><br></span></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Dec 8, 2017 at 9:19 PM, Greg Parker <span dir="ltr"><<a href="mailto:gparker@apple.com" target="_blank">gparker@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Evidence in favor of Slava's analysis: if you remove `func f()` from P itself, leaving it in the extensions only, then you get "T is Int" from both calls.<br>
<div class="m_3843216022228456842HOEnZb"><div class="m_3843216022228456842h5"><br>
<br>
> On Dec 8, 2017, at 12:12 PM, Slava Pestov via swift-users <<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>> wrote:<br>
><br>
> Hi Jens,<br>
><br>
> I think the problem is that overload ranking always prefers a protocol requirement to a protocol extension member, because usually you want the dynamic dispatch through the requirement instead of calling the default implementation. But it appears that this heuristic does not take into account the fact that the protocol extension member could be more constrained than the requirement.<br>
><br>
> Please file a bug, but it is unclear what the desired behavior actually is here. Perhaps it should just diagnose an ambiguity.<br>
><br>
> Slava<br>
><br>
>> On Dec 8, 2017, at 6:25 AM, Jens Persson via swift-users <<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>> wrote:<br>
>><br>
>> Hi all!<br>
>><br>
>> Can someone please explain the rationale behind the last line printing<br>
>> "T is unknown"<br>
>> rather than (what I would expect):<br>
>> "T is Int"<br>
>> in the following program?<br>
>><br>
>><br>
>> protocol P {<br>
>> associatedtype T<br>
>> func f() // *<br>
>> }<br>
>> extension P {<br>
>> func f() { print("T is unknown") }<br>
>> }<br>
>> extension P where T == Int {<br>
>> func f() { print("T is Int") }<br>
>> }<br>
>><br>
>> struct X<T> : P {}<br>
>><br>
>> struct Y<U> where U: P, U.T == Int {<br>
>> // NOTE: The compiler/type-checker knows that U.T == Int here so ...<br>
>> typealias T = U.T<br>
>> var a: U<br>
>> func g() { a.f() } // ... how/why could this print anything but "T is Int"?<br>
>> }<br>
>><br>
>> let x = X<Int>()<br>
>> x.f() // Prints "T is Int", no matter if * is commented out or not.<br>
>><br>
>> let y = Y(a: X<Int>())<br>
>> y.g() // Prints "T is unknown" unless * is commented out. Why?<br>
>><br>
>><br>
>> IMHO this looks like the compiler simply ignores that struct Y<U> has the constraint U.T == Int.<br>
>> How else to explain this behavior?<br>
>> /Jens<br>
>><br>
>> ______________________________<wbr>_________________<br>
>> swift-users mailing list<br>
>> <a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br>
>> <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-users</a><br>
><br>
> ______________________________<wbr>_________________<br>
> swift-users mailing list<br>
> <a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-users</a><br>
<br>
</div></div></blockquote></div><br></div>
______________________________<wbr>_________________<br>swift-users mailing list<br><a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-users" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-users</a><br></div></blockquote></div><br></div></div></div></blockquote></div><br></div>
</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-users mailing list</span><br><span><a href="mailto:swift-users@swift.org">swift-users@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-users">https://lists.swift.org/mailman/listinfo/swift-users</a></span><br></div></blockquote></body></html>