<div dir="ltr"><div>Dipping my toes in the water, so to speak, with a suggestion that came to mind. Not an expert by any means, so hopefully this isn&#39;t too laughably off the mark. As background, I work in the biomedical sciences; with few exceptions, those of us who write code are non-experts who learn as we go along. What&#39;s been attractive about Swift is that it&#39;s been designed with approachability in mind for beginning coders and those with a rudimentary understanding of languages in the C family. Difficulty in syntax and sophistication of the computer science concepts exposed are hurdles that can be overcome, but what keeps me up at night are potentially subtle things maybe easy for the expert that I or my colleagues just might not know about, which then lead to code that appears correct at first glance, compiles, but executes in subtly unintended ways. Those things in my field are what could lead to retracted papers, ruined careers, etc....</div><div><br></div><div>This is something along those lines; also somewhat of a reprise of a theme that&#39;s been raised tangentially in a few threads within the past month (e.g.: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001125.html">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001125.html</a>), but I think the particular solution I&#39;m envisioning hasn&#39;t been put forward.</div><div><br></div><div>The issue at hand:</div><div><br></div><div>Consider the following (contrived) example (call it version 1)--</div><div><br></div><div>class Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;generic sound&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Cow: Animal {</div><div>    override func makeNoise() -&gt; String {</div><div>        return &quot;moo&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Sheep: Animal {</div><div>    override func makeNoise() -&gt; String {</div><div>        return &quot;bah&quot;</div><div>    }</div><div>}</div><div><br></div><div>let cow = Cow()</div><div>cow.makeNoise() // &quot;moo&quot;</div><div>(cow as Animal).makeNoise() // &quot;moo&quot;</div><div><br></div><div>let farm: [Animal] = [Cow(), Cow(), Sheep()]</div><div>let noises: [String] = farm.map { $0.makeNoise() }</div><div>// [&quot;moo&quot;, &quot;moo&quot;, &quot;bah&quot;]</div><div><br></div><div>Now refactor to use a protocol. I&#39;ll give two versions, differing by a single line.</div><div><br></div><div>Version 2A--</div><div><br></div><div>protocol Animal { }</div><div><br></div><div>extension Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;generic sound&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Cow: Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;moo&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Sheep: Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;bah&quot;</div><div>    }</div><div>}</div><div><br></div><div>let cow = Cow()</div><div>cow.makeNoise() // &quot;moo&quot;</div><div>(cow as Animal).makeNoise() // &quot;generic sound&quot;</div><div><br></div><div>let farm: [Animal] = [Cow(), Cow(), Sheep()]</div><div>let noises: [String] = farm.map { $0.makeNoise() }</div><div>// [&quot;generic sound&quot;, &quot;generic sound&quot;, &quot;generic sound&quot;]</div><div><br></div><div>Version 2B--</div><div><br></div><div>protocol Animal {</div><div>    func makeNoise() -&gt; String</div><div>}</div><div><br></div><div>extension Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;generic sound&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Cow: Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;moo&quot;</div><div>    }</div><div>}</div><div><br></div><div>class Sheep: Animal {</div><div>    func makeNoise() -&gt; String {</div><div>        return &quot;bah&quot;</div><div>    }</div><div>}</div><div><br></div><div>let cow = Cow()</div><div>cow.makeNoise() // &quot;moo&quot;</div><div>(cow as Animal).makeNoise() // &quot;moo&quot;</div><div><br></div><div>let farm: [Animal] = [Cow(), Cow(), Sheep()]</div><div>let noises: [String] = farm.map { $0.makeNoise() }</div><div>// [&quot;moo&quot;, &quot;moo&quot;, &quot;bah&quot;]</div><div><br></div><div>To be sure, this difference in behavior can be justified in a variety of ways, but it is nonetheless a surprising result at first glance. Most concerning is that it is possible to imagine a scenario in which the protocol in question is one provided in a third-party library, or even the Swift standard library, while I&#39;m writing a struct or class that implements that protocol.</div><div><br></div><div>Suppose that between versions of a third-party library the Animal protocol changes from version 2A to version 2B. My struct or class that implements the protocol would compile without changes, and cow.makeNoise() would even give the same result, yet there would be differences in how my code works that would be difficult to track down. An expert would be able to spot the difference on examination of the protocol declaration, but one would have to be knowledgeable already about this particular issue to know what to look for. This seems like a gotcha that can be avoided.</div><div><br></div><div>Proposed solution:</div><div><br></div><div>I think others have tried to approach this from a different angle (see, for example: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001933.html">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001933.html</a>). My view is that there are two points potentially to address.</div><div><br></div><div>(1) func makeNoise() -&gt; String { ... } within the protocol extension indicates two different things in versions 2A and 2B (since one is dynamically dispatched and the other is not), yet the syntax is indistinguishable.</div><div><br></div><div>(2) Within a class or struct implementing a protocol, a method with the same name as that of a method in a protocol extension (potentially in another file, maybe not written by the same person) behaves differently depending on whether that method name is declared in the protocol itself (potentially in a third file, written by a third person), yet the syntax is indistinguishable within the implementing class or struct. If the protocol changes, whether a method is dynamically dispatched or statically dispatched could change too, yet code in a class or struct implementing that protocol that now behaves differently compiles all the same; implementors are not clued into the change and may not even be aware that changes such as this could happen.</div><div><br></div><div>What I&#39;m thinking is a light-touch fix that would address (2), which would largely mitigate the consequences of (1). Taking inspiration from syntax used for methods in classes that override methods in superclasses, require methods that override dynamically dispatched default implementations in protocol extensions to use the override keyword. Likewise, forbid the override keyword if the method being implemented instead &#39;masks&#39; (would that be the right word?) a statically dispatched method in a protocol extension which can nonetheless be invoked by upcasting to the protocol.</div><div><br></div><div>In other words, I propose that in the contrived example above, version 2B (which behaves just like version 1) requires syntax just like that of version 1 (in class Cow and class Sheep, override func makeNoise() -&gt; String { ... }). Meanwhile, version 2A, which doesn&#39;t quite behave like version 1, forbids the same syntax. That way, anyone confused about what he or she is getting into when implementing the protocol is notified at compile time, and code that compiles in one scenario will not compile if the underlying protocol declaration changes.</div><div><br></div><div>I suppose quite a good counterargument would be that protocols exist to be implemented, and implementations of methods required for conformance to a protocol shouldn&#39;t need another keyword. I would be inclined to agree, but in this case I&#39;d point out that what would trigger the requirement for use of the override keyword is the presence of a default implementation being overridden, not the mere fact that a method declared within a protocol is being implemented.</div><div><br></div><div>Would this be something that is desirable to other users of the language? Easy to implement?</div><div><br></div></div>