<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Consider this example:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">protocol P {</div></div><div class=""><div class=""> associatedtype T</div></div><div class=""><div class=""> func f() // *</div></div><div class=""><div class="">}</div></div><div class=""><div class="">extension P {</div></div><div class=""><div class=""> func f() { print("T is unknown") }</div></div><div class=""><div class="">}</div></div><div class=""><div class="">extension P where T == Int {</div></div><div class=""><div class=""> func f() { print("T is Int") }</div></div><div class=""><div class="">}</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">struct X<T> : P {</div></div><div class=""><div class=""> func f() { print("this one is actually best") }</div></div><div class=""><div class="">}</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">struct Y<U> where U: P, U.T == Int {</div></div><div class=""><div class=""> typealias T = U.T</div></div><div class=""><div class=""> var a: U</div></div><div class=""><div class=""> func g() { a.f() }</div></div><div class=""><div class="">}</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">let x = X<Int>()</div></div><div class=""><div class="">x.f() // "this one is actually best"</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">let y = Y(a: X<Int>())</div></div><div class=""><div class="">y.g() // "this one is actually best"</div></div></blockquote><div class=""><div class=""><br class=""></div></div><div class="">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 class=""><br class=""></div><div class="">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><div class=""><br class=""></div><div class="">Jordan</div><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Dec 8, 2017, at 13:07, Jens Persson via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">Thanks Slava and Greg,</div><div class=""><br class=""></div><div class="">(</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" class="">unless * is commented out." in</span> the comment of the last line<div class=""><span style="font-size:12.800000190734863px" class="">Note that the "U.T == Int"-part of </span><br class=""></div><div class=""><span style="font-size:12.800000190734863px" class=""> struct Y<U> where U: P, U.T == Int {</span></div><div class=""><span style="font-size:12.800000190734863px" class="">is key here. If it had been only</span></div><div class=""><span style="font-size:12.800000190734863px" class=""> struct Y<U> where U: P {</span><span style="font-size:12.800000190734863px" class=""><br class=""></span></div><div class=""><span style="font-size:12.800000190734863px" class="">then I hadn't been surprised that it printed "T is unknown".</span></div><div class=""><span style="font-size:12.800000190734863px" class="">)</span></div><div class=""><span style="font-size:12.800000190734863px" class=""><br class=""></span></div><div class=""><span style="font-size:12.800000190734863px" class="">Filed </span><a href="https://bugs.swift.org/browse/SR-6564" class="">https://bugs.swift.org/browse/SR-6564</a><span style="font-size:12.800000190734863px" class=""> 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 class=""><span style="font-size:12.800000190734863px" class="">I think I will be a little disappointed if the solution is to deem it an ambiguity</span></div><div class=""><span style="font-size:12.800000190734863px" class="">: )</span></div><div class=""><span style="font-size:12.800000190734863px" class=""><br class=""></span></div><div class="">/Jens</div><div class=""><span style="font-size:12.800000190734863px" class=""><br class=""></span></div><div class=""><span style="font-size:12.800000190734863px" class=""><br class=""></span></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Fri, Dec 8, 2017 at 9:19 PM, Greg Parker <span dir="ltr" class=""><<a href="mailto:gparker@apple.com" target="_blank" class="">gparker@apple.com</a>></span> wrote:<br class=""><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 class="">
<div class="HOEnZb"><div class="h5"><br class="">
<br class="">
> On Dec 8, 2017, at 12:12 PM, Slava Pestov via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:<br class="">
><br class="">
> Hi Jens,<br class="">
><br class="">
> 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 class="">
><br class="">
> Please file a bug, but it is unclear what the desired behavior actually is here. Perhaps it should just diagnose an ambiguity.<br class="">
><br class="">
> Slava<br class="">
><br class="">
>> On Dec 8, 2017, at 6:25 AM, Jens Persson via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:<br class="">
>><br class="">
>> Hi all!<br class="">
>><br class="">
>> Can someone please explain the rationale behind the last line printing<br class="">
>> "T is unknown"<br class="">
>> rather than (what I would expect):<br class="">
>> "T is Int"<br class="">
>> in the following program?<br class="">
>><br class="">
>><br class="">
>> protocol P {<br class="">
>> associatedtype T<br class="">
>> func f() // *<br class="">
>> }<br class="">
>> extension P {<br class="">
>> func f() { print("T is unknown") }<br class="">
>> }<br class="">
>> extension P where T == Int {<br class="">
>> func f() { print("T is Int") }<br class="">
>> }<br class="">
>><br class="">
>> struct X<T> : P {}<br class="">
>><br class="">
>> struct Y<U> where U: P, U.T == Int {<br class="">
>> // NOTE: The compiler/type-checker knows that U.T == Int here so ...<br class="">
>> typealias T = U.T<br class="">
>> var a: U<br class="">
>> func g() { a.f() } // ... how/why could this print anything but "T is Int"?<br class="">
>> }<br class="">
>><br class="">
>> let x = X<Int>()<br class="">
>> x.f() // Prints "T is Int", no matter if * is commented out or not.<br class="">
>><br class="">
>> let y = Y(a: X<Int>())<br class="">
>> y.g() // Prints "T is unknown" unless * is commented out. Why?<br class="">
>><br class="">
>><br class="">
>> IMHO this looks like the compiler simply ignores that struct Y<U> has the constraint U.T == Int.<br class="">
>> How else to explain this behavior?<br class="">
>> /Jens<br class="">
>><br class="">
>> ______________________________<wbr class="">_________________<br class="">
>> swift-users mailing list<br class="">
>> <a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
>> <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-users</a><br class="">
><br class="">
> ______________________________<wbr class="">_________________<br class="">
> swift-users mailing list<br class="">
> <a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
> <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-users</a><br class="">
<br class="">
</div></div></blockquote></div><br class=""></div>
_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></div></blockquote></div><br class=""></body></html>