<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, May 23, 2016 at 6:58 AM, Matthew Johnson <span dir="ltr">&lt;<a href="mailto:matthew@anandabits.com" target="_blank">matthew@anandabits.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><div><br><br>Sent from my iPad</div><span class=""><div><br>On May 22, 2016, at 11:55 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sun, May 22, 2016 at 11:20 PM, Matthew Johnson <span dir="ltr">&lt;<a href="mailto:matthew@anandabits.com" target="_blank">matthew@anandabits.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><br><div><span><blockquote type="cite"><div>On May 22, 2016, at 4:22 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br><div><div dir="ltr">On Sun, May 22, 2016 at 3:38 PM, Brent Royal-Gordon via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span>&gt; The proposal is well thought out and makes a valiant attempt at handling all of the issues necessary.  But I don&#39;t support it for a number of reasons.  I think it highlights how awkward it would be to try to address shadowing on a case-by-case basis, which isn&#39;t necessarily obvious until you explore what a solution might look like.<br>
<br>
</span>It does, but I&#39;m just not sure what else you can do about it. If there&#39;s a warning, you need a way to silence it. If you ignore some cases (like creating a conflict by importing two modules), you&#39;ll miss some of the subtlest and hardest-to-fix bugs.<br>
<br>
Honestly, I&#39;m tempted to say &quot;you just can&#39;t ever shadow a final protocol method&quot; and be done with it. If that prevents certain conformances or stops certain imports, so be it. You can always work around that with wrapper types or other techniques.<br></blockquote><div><br></div><div>You know, I think this might be cleverest solution. It adds a small limit to the language, but it doesn&#39;t unduly penalize retroactive modeling. If you control either the protocol or the conforming type, you can change the name of one of the methods so it doesn&#39;t shadow/get shadowed by the other.</div></div></div></div></div></blockquote><div><br></div></span><div>If you control the conforming type this isn’t too big an issue as long as the protocol was well designed.  However, if the protocol was poorly designed it could be an issue.  Maybe a method that can be more efficiently implemented by some types was not made a requirement, but an extension method (with a slower implementation) takes the obvious name.  Maybe you would be willing to live with the slower implementation when your type is accessed via the protocol, because at least it can still be used via the protocol, but you don’t want to burden callers who use the concrete type with the slow implementation.  What do you do then? </div></div></div></blockquote><div><br></div><div>If a method that really ought to be a protocol requirement isn&#39;t a requirement and you don&#39;t control the protocol, well you&#39;re pretty much out of luck even today. Any conforming type accessed via the protocol will use the less efficient extension method and nothing about Brent&#39;s proposal would make that worse or better.</div><div><br></div><div>Shadowing of the slow extension method doesn&#39;t remove the burden. It may make calling your fast implementation look nicer, but a less informed user of your type would unwittingly call the slower implementation if they access your type via the protocol. You could instead:</div><div>* come up with another name for your fast implementation; maybe the &quot;obvious&quot; name for the method is &quot;frobnicate&quot;--then name your method &quot;quicklyFrobnicate&quot;;</div></div></div></div></div></blockquote><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>* or, decide you don&#39;t want to conform your type to a poorly designed protocol after all, instead retroactively modeling your type and other types of interest with a better designed protocol of your making.</div></div></div></div></div></blockquote><div><br></div></span><div>Maybe you want the type to inter operate with code you don&#39;t control and in order to do that it must conform to the protocol.  And you don&#39;t want to obfuscate the interface to the concrete type because the protocol is poorly designed.</div></div></blockquote><div><br></div><div>I&#39;m not sure this is a reasonable set of demands. I understand a protocol to be a contract. If you decide to conform to a poorly designed protocol, you *should* have a poorly designed concrete type. That is the purpose of a protocol, to provide certain guarantees, be they wise or unwise. To me, it&#39;s a bug rather than a feature to support papering over poor protocol design when conforming to a protocol, which also forces the poor design to be exposed only when accessing your type through that protocol. In the end, you don&#39;t have a well-designed type; your type is instead simultaneously well and poorly designed!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><div>  Conforming to the protocol *is not* the primary reason your type exists - conformance is used only for the purpose of using your type with a specific piece of third party code.</div><div><br></div><div>You *could* wrap your type for the purpose of this conformance.  This is what a Brent alluded to.  But it requires boilerplate and a bunch of conversion operations.  This is not just annoying, it could also be complex enough to lead to bugs.</div><span class=""><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div>If you control the protocol but want to retroactively model types you do not control this assumes you are willing to design your protocol around those types.  What if one of those types happens to implement a method that should not be a requirement of the protocol for one reason or another, but will be implemented as an extension method.  What do you do then?<br></div></div></div></blockquote><div><br></div><div>I&#39;m not sure I quite understand when this arises. Surely, by construction, if you wish to retroactively model types, you are willing to design your protocol around them. What else could it mean to retroactively model existing types? Can you give a concrete example where during retroactively modeling you simply have no choice but to name an extension method using a name that it is shadowed by a conforming type?</div></div></div></div></div></blockquote><div><br></div></span>I&#39;m not saying you have *no choice*.  But again, conforming the one problematic type is not the primary purpose for which you are designing the protocol.  You know the shadowing method will not present any problems for your design.  Why should you be forced to design your protocol around this?</div></blockquote><div><br></div><div>Because, again, a protocol is a contract. If you&#39;re retroactively modeling many well designed types and one poorly designed type, the lowest common denominator is a poorly designed protocol. That *should* be the result, no?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class=""><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div></div><div>And of course there are cases where you do not control either.   Some people write code with a lot of 3rd party dependencies these days (not my style, but pretty common).  This is not a trivial concern.<br></div></div></div></blockquote><div><br></div><div>You are saying that it would be possible for a protocol extension in one dependency to conflict with a conforming type in another? This issue can be avoided if enforcement of non-shadowing by the compiler is such that when neither conforming type nor protocol extension is under your control everything continues to work as-is.</div></div></div></div></blockquote><div><br></div></span><div>So you would still allow the developer to declare the conformance without error?  This means that developers still need to understand the shadowing behavior but it is pushed even further into a dark corner of the language with more special case rules that must be learned to understand when you might run into it.</div></div></blockquote><div><br></div><div>No, I would forbid declaring any such conformance in code the developer controls. If you control the conforming type and it contains a method name that clashes with a protocol extension method, you would be forbidden from declaring conformance without renaming your clashing method. In fact, I&#39;m beginning to wonder if protocol extension methods on protocols outside the same module should be internally scoped.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class=""><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><span><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span><br>
&gt; (And btw, &#39;final&#39; in this proposal is not exactly, because when combined with @incoherent the methods are not actually &#39;final&#39; - there is a necessary escape hatch).<br>
<br>
</span>There is no particular reason you couldn&#39;t allow similar annotated shadowing of `final` methods on classes; they would have basically the same semantics as you get here, where if a piece of code knows it&#39;s working with the subclass you get subclass semantics, but otherwise you get superclass ones. I do not claim this is a good idea. :^)<br>
<span><br>
&gt; Second, we should require annotation of methods in protocol extensions that are not default implementation of requirements.  Maybe &#39;shadowable&#39; or &#39;staticdispatch&#39;?  These are awkward, but so is the behavior and they describe it better than anything else I&#39;ve seen so far (maybe we can do better though).<br>
<br>
</span>I don&#39;t think `shadowable` makes sense here; that doesn&#39;t acknowledge a limitation, which is what we&#39;re trying to do here.<br>
<br>
I continue to wish we hadn&#39;t taken `static` for statically-dispatched type methods. But I lost that argument years before swift-evolution became a thing.<br>
<span><br>
&gt; I don&#39;t like &#39;nondynamic&#39; both because it is not aligned with the meaning of &#39;dynamic&#39; and also because it only says what the behavior *is not* rather than what the behavior *is*.<br>
<br>
</span>I do understand what you mean here. Unfortunately, the word &quot;virtual&quot; in a keyword makes me break out in hives, and I&#39;m not sure what else we might base it on.<br>
<br>
This is why I selected `final` in my proposal. `final` is desperately close to the actual semantic here, far closer than anything else in the language.<br></blockquote><div><br></div><div>How about `nonoverridable`? That said, I agree with earlier comments that training-wheel annotations probably aren&#39;t the way to go. Maybe, as you suggest above, just don&#39;t allow shadowing at all.</div></div></div></div></div></blockquote><div><br></div></span><div>Unfortunately, ‘nonoverridable’ doesn’t really make sense because you don’t ‘override’ protocol requirements.</div></div></div></blockquote><div><br></div><div>You don&#39;t override protocol requirements, but you do override their default implementations, whereas you cannot &#39;override&#39; statically dispatched extension methods. Within a protocol extension, there are methods that are overridable by conforming types (i.e. default implementations of protocol requirements) and methods that are not (i.e. statically dispatched non-requirements).</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><span><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div><div><br>
--<br>
Brent Royal-Gordon<br>
Architechies<br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div></div>
</div></blockquote></span></div><br></div></blockquote></div><br></div></div>
</div></blockquote></span></div></blockquote></div><br></div></div>