<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"><meta http-equiv="Content-Type" content="text/html charset=utf-8"><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=""><div class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">I must admit I'm having difficulty understanding why it's a big deal whether the dispatch will be static or dynamic. This seems like an implementation detail; any "dynamic dispatch" in the aforementioned sense can actually became static for a final class.</div></div></div></div></blockquote></div><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><div class="">It’s not just an implementation detail. The original article demonstrates this compellingly, I think.</div><div class=""><br class=""></div><div class="">Yes, it’s true that, as an optimization, the compiler can choose to use static dispatch in situations where doing so makes no difference (e.g. calling a final method, calling a private method with no overrides, etc.).</div><div class=""><br class=""></div><div class="">However, there are situations where static dispatch changes the behavior of the code. At that point, it’s a semantic difference. It’s those cases I’m concerned about.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">Just think about function defined as having a "magic prefix" that corresponds technically to vtable where they can be located:</div></div></div></div></blockquote></div></div></div></div></div><div class=""><br class=""></div><div class="">It’s not that it’s hard to understand what’s happening if you <i class="">already know</i> that a call uses static dispatch. The problem is that it’s difficult to determine <i class="">whether it does</i>.</div><div class=""><br class=""></div><div class="">• • •</div><div class=""><br class=""></div><div class="">Note that your example code with C_f and P_f does not demonstrate the problem at hand. It’s worth working through why.</div><div class=""><br class=""></div><div class="">Translating your pseudocode into actual Swift, this does not compile:</div><div class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">class</span> C {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span> f() {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">print</span>(<span style="font-variant-ligatures: no-common-ligatures; color: #843e64" class="">"C_f"</span>)</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; min-height: 12px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">protocol</span> P {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span> f()</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; min-height: 12px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">extension</span> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">C</span>: <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">P</span> {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; color: rgb(102, 139, 73);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> f() { </span>// compiler error here</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">print</span>(<span style="font-variant-ligatures: no-common-ligatures; color: #843e64" class="">"P_f"</span>)</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal;" class=""> }</div><div class=""><br class=""></div></div><div class="">I imagine that you were thinking of something along these lines:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">class</span> C {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span> f() {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">print</span>(<span style="font-variant-ligatures: no-common-ligatures; color: #843e64" class="">"C_f"</span>)</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; min-height: 12px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">protocol</span> P {</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span> f() <span style="color: rgb(102, 139, 73);" class="">// remember this line</span></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; min-height: 12px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; color: rgb(50, 62, 125);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span>extension<span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">P</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> {</span></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; color: rgb(102, 139, 73);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> f() {</span></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">print</span>(<span style="font-variant-ligatures: no-common-ligatures; color: #843e64" class="">"P_f"</span>)</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; min-height: 12px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">extension</span> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">C</span>: <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">P</span> { } <span style="color: rgb(102, 139, 73);" class="">// C: P now separate from extension impl of f()</span></div><p style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo; min-height: 12px;" class=""><span style="font-size: 10.5px;" class=""><br class=""></span></p><div class="">However, this does not behave as you think it does:</div><div class=""><br class=""></div><p style="margin: 0px; line-height: normal; min-height: 12px;" class=""><span style="font-family: Menlo; font-size: 10.5px;" class=""> </span><span style="font-family: Menlo; font-size: 10.5px;" class="">(</span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">C</span><span style="font-family: Menlo; font-size: 10.5px;" class="">() </span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(50, 62, 125);" class="">as</span><span style="font-family: Menlo; font-size: 10.5px;" class=""> </span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">C</span><span style="font-family: Menlo; font-size: 10.5px;" class="">).</span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">f</span><span style="font-family: Menlo; font-size: 10.5px;" class="">()</span><font face="Menlo" size="1" class=""> </font><font color="#668b49" face="Menlo" size="1" class="">// </font><font color="#668b49" face="Menlo" class=""><font size="1" class="">C_f</font></font></p><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> (<span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">C</span>() <span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">as</span> <span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">P</span>).<span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">f</span>()<font face="Menlo" size="1" class=""> </font><font color="#668b49" face="Menlo" size="1" class="">// </font><font color="#668b49" face="Menlo" class=""><font size="1" class="">C_f</font></font></div></div><div class=""><br class=""></div><div class="">However <i class="">again</i>, if you remove the line marked “remember this line,” <i class="">then</i> the code does do what you think it does:</div><div class=""><br class=""></div><div class=""><div class=""><div style="margin: 0px; line-height: normal; min-height: 12px;" class=""><span style="font-family: Menlo; font-size: 10.5px;" class=""> </span><span style="font-family: Menlo; font-size: 10.5px;" class="">(</span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">C</span><span style="font-family: Menlo; font-size: 10.5px;" class="">() </span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(50, 62, 125);" class="">as</span><span style="font-family: Menlo; font-size: 10.5px;" class=""> </span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">C</span><span style="font-family: Menlo; font-size: 10.5px;" class="">).</span><span style="font-family: Menlo; font-size: 10.5px; color: rgb(88, 126, 168);" class="">f</span><span style="font-family: Menlo; font-size: 10.5px;" class="">()</span><font face="Menlo" size="1" class=""> </font><font color="#668b49" face="Menlo" size="1" class="">// </font><font color="#668b49" face="Menlo" class=""><font size="1" class="">C_f</font></font></div><div style="margin: 0px; font-size: 10.5px; line-height: normal; font-family: Menlo;" class=""> (<span style="color: rgb(88, 126, 168);" class="">C</span>() <span style="color: rgb(50, 62, 125);" class="">as</span> <span style="color: rgb(88, 126, 168);" class="">P</span>).<span style="color: rgb(88, 126, 168);" class="">f</span>()<font face="Menlo" size="1" class=""> </font><font color="#668b49" face="Menlo" size="1" class="">// P</font><font color="#668b49" face="Menlo" class=""><font size="1" class="">_f</font></font></div></div></div><div class=""><font color="#668b49" face="Menlo" class=""><font size="1" class=""><br class=""></font></font></div><div class="">I’d say that if you got confused in the course of explaining how it's not confusing … well, that’s pretty good evidence that it is indeed confusing.</div><div class=""><br class=""></div><div class="">Cheers,</div><div class=""><br class=""></div><div class="">Paul</div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 7, 2015, at 3:56 PM, ilya <<a href="mailto:ilya.nikokoshev@gmail.com" class="">ilya.nikokoshev@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><br class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Mon, Dec 7, 2015 at 7:17 AM, Paul Cantrell via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">One of the few things in Swift 2 that feels to me like a design flaw is the way Swift mixes static and dynamic method dispatch.<br class="">
<br class="">
Alexandros Salazar gives an excellent explanation of this problem — and I agree wholeheartedly with his title for the article:<br class="">
<br class="">
<a href="http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future" rel="noreferrer" target="_blank" class="">http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future</a><br class="">
<br class="">
The upshot is that when we see this:<br class="">
<br class="">
foo.bar()<br class="">
<br class="">
…it’s very hard to know how the compiler will determine which implementation of bar() to use. It might use static dispatch; it might use dynamic dispatch.<br class="">
<br class="">
The rules that govern this are arcane, and hard to remember. They have the feeling of being a “gotcha” question for job interviews — always a red flag for language features.<br class="">
<br class="">
Even if you remember the rules, the information needed to determine whether dispatch is static or dynamic is hard to track down. It depends on whether bar()’s implementation comes from an extension, whether the extension method appeared on the extended protocol, and whether the inferred type of foo is the protocol itself or an implementing type.<br class="">
<br class="">
A crucial part of the meaning of “foo.bar()” is implicit, and hard to determine. </blockquote><div class=""><br class=""></div><div class="">I must admit I'm having difficulty understanding why it's a big deal whether the dispatch will be static or dynamic. This seems like an implementation detail; any "dynamic dispatch" in the aforementioned sense can actually became static for a final class.</div><div class=""><br class=""></div><div class="">I understand there can be a confusion about the method called when the protocol contains a method implementation, but there are some simple ways to understand why things work as they do. Just think about function defined as having a "magic prefix" that corresponds technically to vtable where they can be located:</div><div class=""><br class=""></div><div class="">class C {</div><div class=""> func C_f // declares C.C_f</div><div class="">}</div><div class=""><br class=""></div><div class="">protocol P {</div><div class=""> func P_f</div><div class="">}</div><div class=""><br class=""></div><div class="">// implementation of P.P_f</div><div class=""><br class=""></div><div class="">extension C:P {</div><div class=""> // declares that C.C_f = C.P_f</div><div class="">}</div><div class=""><br class=""></div><div class="">(C() as C).f -> calls C.C_f = C.P_f</div><div class="">(C() as P).f -> calls P.P_f</div><div class=""> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This runs contrary to Swift’s stated goal of prioritizing clarity at the point of API use, and its general pattern of making intent explicit. And it feels dangerous — a wellspring of insidious bugs.<br class="">
<br class="">
Thus:<br class="">
<br class="">
<br class="">
PROPOSAL<br class="">
<br class="">
Make the syntax “foo.bar()” always use dynamic dispatch, i.e. always use _only_ the runtime type of foo to determine which implementation of bar() to use. If an extension method collision occurs when a type implements multiple protocols, require the type to explicitly specify which one to use (as Swift already requires the caller to do at the point of invocation).<br class="">
<br class="">
<br class="">
I mean this proposal somewhat as a strawman. It’s such an obvious choice, I’m sure there were good reasons not to do it. But I’d like to propose the obvious solution in order to understand what’s wrong with it. I realize static dispatch precludes some optimizations, but I doubt that this alone drove the design choice. I see no safety or expressiveness upside to the way it works now.<br class="">
<br class="">
Cheers,<br class="">
<br class="">
Paul<br class="">
<br class="">
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div><br class=""></div></div>
</div></blockquote></div><br class=""></body></html>