<div dir="ltr">Building on Haravikk&#39;s suggestion:<div><br></div><div>    1. Make methods and classes final by default and mark an overridable class with `class(option)` or `class(replace)` (see below for `class(replace)`).</div><div>    2. A function declaration requires one of `func`, `func(final)`, `func(replace)`, `func(option)`, `func(before)`, `func(after)`, or `func(instead)` keywords and a function override requires one of `override`, `override(final)`, `override(replace)`, `override(option)`, `override(before)`, `override(after)`, or `override(instead) - note no func keyword.</div><div>    3. A change from Haravikk&#39;s suggestion, retain the current meaning of override (with different notation) so that `override(option)` means that you can call super anywhere or not at all. (Equivalent to current `override`.)</div><div>    4. Establish a hierarchy, since the override becomes part of the method&#39;s public signature, in particular: </div><div>        4.a. `func/override(replace)` can be overridden/implemented by any form, i.e. one of `override(replace)`, `override(replace, option)`, `override(replace, before)`, `override(replace, after)`, and `override(replace, instead)`. (Note the two qualifiers: what you are going from to what you are going to.)</div><div>        4.b. `func/override(option)` can be overridden/implemented by `override(option)`, `override(option, before)`, `override(option, after)`, or `override(option, instead)`.</div><div>        4.c. `func/override(before)`, `func/override(after)`, and `func/override(instead)` can only be overridden/implemented by the same modifier.</div><div>    5. Methods in protocols and classes that do not have a body are automatically `func/override(replace)`. (Currently protocols cannot have bodies, but that is likely to change.) Final methods must have a body, i.e. `func(final) method()` is an error because it is final and has no body.</div><div>    6. A class with a method without a body, which must be marked `func/override` or `func/override(replace)`, has to be marked `class(replace)`; it is abstract. (Note the notation `class(option)` and `class(replace)` is consistent, a `class(option)` has at least one optionally overridable method and no `func/override(replace)` methods, whereas a class with at least one `func/override(replace)` method is marked `class(replace)`.)</div><div>   7. Any of the annotations can be extended with final, e.g. `func(optional, final)` means it is overriding a `func(optional)` but from this point down it is final. Final methods must have a body.</div><div>   8. In a class/protocol `func` is shorthand for `func(final)` unless the method has no body in which case it is shorthand for `func(replace)`.</div><div>   9. `override` is a shorthand for `override(A, final)` where A is the annotation specified in the matching `func` declaration.</div><div>   10. Overriding methods in a final class do not require the extra final annotation, e.g. in a final class `func(option)` and `func(option, final)` are equivalent.</div><div><br></div><div>EG:</div><div><br></div><div><div>    class(replace) Abstract { // Point 1: class marked as replace, it is therefore abstract and you can&#39;t call init. Point 6: it has an abstract method therefore must be abstract itself.</div><div>        func abstract() // Point 5: declare an abstract method (it has no body), equivalent to `func(replace)`.</div><div>        </div><div>        func(option) overridable() { // Point 2: declare an optionally overridable method. Point 3: same override semantics as Swift 2.</div><div>            print(&quot;Optionally overridable with any super call OK&quot;) </div><div>        }</div><div>        </div><div>        func finalFunc() { // Point 1: methods are final by default. Point 8: `func` is shorthand for `func(final)` when the method has a body.</div><div>            print(&quot;Method is final&quot;)</div><div>        }</div><div>    }</div><div>    </div><div><div>    class Final: Overridable { // Point 1: class is final since it isn&#39;t annotated.</div><div>        override abstract() { // Point 2: override keyword not func. Point 7: method is final because class is final. Point 9: `override` is equivalent to `override(replace, final)`.</div><div>            print(&quot;Implementation of abstract method&quot;)</div><div>        }</div><div>        </div><div>        override overridable() { // Point 2: override keyword not func. Point 7: method is final because class is final. Point 9: `override` is equivalent to `override(option, final)`.</div><div>            print(&quot;Method is final because class is final&quot;) </div><div>        } <br></div></div><div>    }</div><div>    </div><div><div>    class(option) Derived: Overridable { // Point 1: class is overridable because it is annotated option.</div><div>        override(replace, after) abstract() { // Point 4.a: implementation of an abstract class</div><div>            print(&quot;In a derived class this will be printed after the derived class&#39;s body has finished&quot;)</div><div>        }</div><div>        </div><div>        override(option, final) overridable() { // Point 7: method is final because it is annotated final.</div><div>            print(&quot;Method is final because class is final&quot;) </div><div>        } <br></div></div><div>    }</div><div><br></div></div></div><div class="gmail_extra"><br clear="all"><div><div class="gmail_signature">  -- Howard.<br></div></div>
<br><div class="gmail_quote">On 16 February 2016 at 09:56, Haravikk 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><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Oh, it looks like Alexey beat me to a similar solution, but split the thread (at least in Mail.app):</div><div><br></div><blockquote type="cite">On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br></blockquote><blockquote type="cite">Hi<br><br>I would like to suggest you to extend your proposal.<br><br>In my practice, overriding super functions can have several semantics.<br>1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.<br>2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.<br>3) Before super - opposite to 2.<br>4) Override - no rules about order, but super call must be done. <br><br>So code can look like: <br><br>override(after) func viewDidLoad() {<br>   // super.viewDidLoad() &lt;— no need to call super at first line.<br>   // child code<br>}<br><br>override(before) func tearDown() {<br>   // clean code<br>   // super… inserted by compiler<br>}<br><br>override(instead) func loadView() {<br>   // super.loadView() &lt;— marked as an error with appropriate fix-up to remove instead modifier<br>}<br><br>override func refillHealthBar() {<br>  // absent call to super will cause an error with fix-up to add (instead) modifier<br>}<br><br>I am not sure about exposing this in a public interface and limit child override options.<br><br><div>But in general - what is your thoughts about this approach to problem that you mention?</div></blockquote><div><div class="h5"><br><div><blockquote type="cite"><div>On 15 Feb 2016, at 22:52, Haravikk via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br><div><div style="word-wrap:break-word"><div>This is an interesting idea, and fits well with the theme of preventing mistakes in Swift, but I think that the proposed solution isn’t flexible enough, as there are cases for inheritance patterns where extending doesn’t actually make sense, so having to specify an exception every time could quickly become annoying.</div><div><br></div><div>I think the better solution is to instead allow super-classes to specify whether or not their method must be called when overridden/extended. For example:</div><div><br></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>class View {</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                </span>@super(required) func viewDidLoad() { … }</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>}</font></div><div><font face="Monaco"><br></font></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>class Button : View {</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                </span>override func viewDidLoad() { … }</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>}</font></div><div><font face="Monaco"><br></font></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>class Widget : View {</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                </span>override func viewDidLoad() {</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                        </span>super.viewDidLoad()</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                        </span>…</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">                </span>}</font></div><div><font face="Monaco"><span style="white-space:pre-wrap">        </span>}</font></div><div><br></div><div>In this extension of your example Button will cause an error because it overrides viewDidLoad() but fails to call the parent’s method as required by the @super attribute. However, Widget compiles successfully because it follows the requirement.</div><div><br></div><div>So the options for @super would be:</div><div><br></div><div><ul><li><b>required: </b>child-class must call parent implementation of this method.</li><li><b>optional:</b> default behaviour, child can choose whether to call the parent’s method.</li><li><b>denied:</b> child may not call parent’s method (useful if it makes assumptions that a child-class may not follow), but can still extend/override.</li></ul><div><br></div></div><div>I think this would be a more flexible solution to the problem, and put the decision in the hands of those writing classes designed for inheritance. I’m not 100% sure of whether to rename override to extend, I like extend better personally, but it probably doesn’t matter overall.</div><br><div><blockquote type="cite"><div>On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br><div>Hi!<br><br>I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).<br>The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:<br><br>class View {<br>   func viewDidLoad() {<br>      // does something<br>   }<br>}<br><br>class Button: View {<br>  override func viewDidLoad() {<br>      super.viewDidLoad()   // &lt;— this might be forgotten<br>      // do something other<br>   }<br>}<br><br>The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.<br><br>// Example for extending a function<br>class Button: View {<br>  extend func viewDidLoad() {<br>      super.viewDidLoad()<br>      // do something<br>   }<br><br>  extend func viewDidAppear() {<br>      // do something<br>   } // &lt;— the compiler should throw an error here.<br>}<br><br>// Example for replacing a function<br>class Geometry {<br>   func volume() -&gt; Double {<br>      return 0;<br>   }<br>}<br><br>class Cube: Geometry {<br>   var length: Double = 0.0<br>   replace func volume() -&gt; Double {<br>      let v = length * length * length<br>      return v<br>   }<br>}<br><br>Cheers,<br>Florian<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" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div>_______________________________________________<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" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div></div></div><br>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">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>
<br></blockquote></div><br></div>