<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>In response to Jordan Rose's comment I suggest the following change:</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature"><p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Proposal: Split extension usage up into implementing methods and adding static functions</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Currently extension methods are confusing because they have different dispatch rules for the same syntax. EG:</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; protocol P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m()</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; extension P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m() { print("P.m") }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; struct S: P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m() { print("S.m") }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; val p: P = S() // Note typed as P</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; p.m() // Surprisingly prints P.m even though S implements its own m</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; val s = S() // Note typed as S</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; s.m() // Prints S.m as expected&nbsp;</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">This proposal cures the above problem by separating extension methods into two seperate use cases: implementations for methods and adding static functions.&nbsp;</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">First implementing methods.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">If the extension is in the same file as the protocol/struct/class declaration then it implements the methods and is dispatched using a Vtable. EG:</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">File P.swift</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; protocol/struct/class P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m()</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; extension P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m() { print("P.m") }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Same or other file</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; struct S: P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; override func m() { print("S.m") } // Note override required because m already has an implementation from the extension</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; val p: P = S() // Note typed as P</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; p.m() // Now prints S.m as expected&nbsp;</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Extensions in the same file as the declaration can have any access, can be final, and can have where clauses and provide inheritable implementations.&nbsp;</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">The implementation needed to achieve this is that a value instance typed as a protocol is copied onto the heap, a pointer to its Vtable added, and it is passed as a pointer. IE it becomes a class instance. No change needed for a class instance typed as a protocol.&nbsp;</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">The second use case is adding static functions.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">A new type of extension is proposed, a static final extension, which can be either in or outside the file in which the protocol/struct/class declaration is in. EG:</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; static final extension P { // Note extension marked static final</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; func m() { print("P.m") }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Which is called as any other static function would be called:</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; val s = S()</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; P.m(s) // Prints P.m as expected</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">The new static final extension is shorthand, particularly in the case of multiple functions, for:</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; extension P {</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; &nbsp; &nbsp; static final func m(_ this: P) { print("P.m") }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">&nbsp; &nbsp; }</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">If the static final extension is outside of the file in which the protocol/struct/class declaration is in then the extension and the methods can only have fileprivate and internal access.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">As at present protocol/struct/class can have both a static and instance method of the same name, m in the case of the example, because the usage syntax is distinct. As at present, static final extensions, both the extension and the individual functions, can have where clauses.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">In summary.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">The proposal formalises the split use of extensions into their two uses: implementing methods and adding static functions. Syntax is added that clarifies both for declarations and usage which type of extension is provided/in use.</span></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69); min-height: 20.3px;"><span style="font-family: '.SFUIText'; font-size: 17pt;"></span><br></p>
<p style="margin: 0px; line-height: normal; font-family: '.SF UI Text'; color: rgb(69, 69, 69);"><span style="font-family: '.SFUIText'; font-size: 17pt;">Note the distinction between an extension in the same file and in a separate file is consistent with the proposed use of private in <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0169-improve-interaction-between-private-declarations-and-extensions.md">https://github.com/apple/swift-evolution/blob/master/proposals/0169-improve-interaction-between-private-declarations-and-extensions.md</a>.</span></p><div id="AppleMailSignature"><br></div>Comments?</div><div id="AppleMailSignature"><br>-- Howard.</div><div><br>On 7 Apr 2017, at 4:49 am, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=us-ascii"><div class="">[Proposal:&nbsp;<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0164-remove-final-support-in-protocol-extensions.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0164-remove-final-support-in-protocol-extensions.md</a>]</div><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 5, 2017, at 16:15, Howard Lovatt via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">The review of SE-0164 "Remove final support in protocol extensions"</span></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><ul class="" style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px;"><li class="" style="box-sizing: border-box;"><font class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">What is your evaluation of the proposal?</span></font></li></ul></blockquote><div class="">The present situation isn't great. People get confused about which method will called with protocol extensions. Seems like every week there is a variation on this confusion on Swift Users mailing list. Therefore something needs to be done.&nbsp;</div><div class=""><br class=""></div><div class="">However I am not keen on this proposal since it makes behaviour inconsistent between methods in protocol extensions, classes, and structs.&nbsp;</div><div class=""><br class=""></div><div class="">I think a better solution would be one of the following alternatives:</div><div class=""><br class=""></div><div class="">&nbsp; 1. Must use final and final means it cannot be overridden; or</div><div class="">&nbsp; 2. If not final dispatches using a table like a class and if marked final cannot be overridden and if marked dynamic uses obj-c dispatching; or</div><div class="">&nbsp; 3. Must be marked dynamic and uses obj-c dispatching.&nbsp;</div><div class=""><br class=""></div><div class="">My preference would be option 2 but I think any of the three is superior to the present situation or the proposal.&nbsp;</div></div></div></blockquote><div><br class=""></div><div>People have suggested all of these before, but none of them are obviously correct. It's true that we have a difference between extension members that satisfy requirements and those that don't, and that that confuses people. However, an extension-only member of one protocol can be used to satisfy the requirements of another protocol today, which is a tool for code reuse.</div><div><br class=""></div><div>(I <i class="">think</i>&nbsp;we managed to convince everyone that it's just a bug that a protocol extension method that satisfies a requirement cannot be overridden in a subclass, so at least that isn't an issue on top of the rest of this.)</div><div><br class=""></div><div>Oh, and we can't retroactively add members of a protocol extension to existing adopters, which is why protocol extension members cannot be @objc. There are limited circumstances where that would be safe, but that would be a separate proposal.</div><div><br class=""></div><div>Jordan</div></div></div></blockquote></body></html>