[swift-evolution] Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall

Haravikk swift-evolution at haravikk.me
Tue Feb 16 16:16:03 CST 2016


Woah, pretty expansive and well thought out set of rules here!

> On 16 Feb 2016, at 03:36, Howard Lovatt <howard.lovatt at gmail.com> wrote:
> 
>     1. Make methods and classes final by default and mark an overridable class with `class(option)` or `class(replace)` (see below for `class(replace)`).

This is a great idea, it’s definitely better to force the developer to think about extension and explicitly declare it, and having the whole thing self-documenting will make it so much easier.

>     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.

I’m not so sure about putting this into the keywords. Personally I think an attribute is a bit neater (it can go nicely above the function declaration). Meanwhile with override I think it’s probably enough to just override a method, as this implicitly agrees to whatever rules were set out by the super-method. If want to put your own requirements on sub-classes even further down the chain then you just add the attribute to your own method.

>     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)`.)

I like this, but would an abstract keyword not be simpler and clearer to most? Setting it on a class would allow that class to contain abstract methods (and properties?) also declared with the abstract keyword. An abstract method could contain no body (child class must give full implementation) or could include a body in which case it must be extended and called.

>    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.
>    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)`.
>    9. `override` is a shorthand for `override(A, final)` where A is the annotation specified in the matching `func` declaration.
>    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.

I think my preference is still towards an attribute to specify the requirements for sub-classes overriding a method, with the override keyword implicitly agreeing to those conditions rather than having to repeat them. If you want to change those requirements for further levels of sub-class then you can just add the same attribute your own methods, like so:

	class MyClass {
		@super(required)
		func mustCallMe() { … } // Immediate sub-classes must call this method

		@super(optional)
		func someOtherMethod() { … } // Call super, or not, this method doesn’t care
	}

	class MySubClass : MyClass {
		@super(before)
		override func mustCallMe() { … } // Further sub-classes must now call this first

		override func someOtherMethod() { … } 	// This implicitly agrees to optionally include the parent call and 
							// is final due to the lack of a @super attribute of its own (or one on its class).
	}

If an overriding method has no @super attribute of its own then it is implicitly final, unless the attribute is instead placed on the class (allowing us to make a class’ methods all overridable if we like). 

I dunno, it may just be personal preference; I can completely get wanting to clarify what rules are being followed at each step, but I’m just unsure whether the extra complexity is worth it? I can definitely see the need to introduce more options over the three I gave though, giving us:

required: parent method must be called somewhere in all code paths of overriding method.
optional: parent method may or may not be called anywhere in the overriding method.
replace: parent method may not be called at all by overriding method (sub-class must provide total replacement).
before and after: these imply required but can also be set as optional (to be read as “if included, parent call must come first/last”). Not sure if after should require the parent method’s return value to be used in methods with a return type?

I think that abstract methods and classes should probably be a separate proposal building upon these extension requirements. In essence though an abstract method with no body would imply @super(replace). An abstract method with a body implies @super(required), but could anything other than @super(replace) would be valid, allowing an abstract class to provide a sample implementation that need not be used in sub-classes, optionally setting a before/after requirement in the event that it is used.

Thoughts? I’m not too fussy about the exact syntax, but I think that while repeating the requirements in the override is explicit (which is usually a good thing) I personally think that the override keyword alone should suffice, as anyone creating a sub-class should know what the requirements of the parent are and agreed to them. What’s important is really whether the overriding method itself has any requirements for classes further down the hierarchy I think.

I also think it could be interesting to allow @super on the class itself, allowing the developer to decide if they want to keep the implicitly final default, or make their methods implicitly overridable, in which case they can then use the final keyword to put it back again.

Lastly, I’m not sure about the use of an attribute actually as I’m not clear on what the rules for them really are (if there are any?). I quite like how they look and they’re already setup to support multiple options etc., but adding options to a keyword may make sense. If we do that though then personally I think we could just re-use super, e.g-:

	class MyClass {
		super(required) func mustCallMe() { … }
	}

I suppose there’s no reason this couldn’t go on func() like you suggest, but I like the consistency with the fact that it’s the super keyword in the method body that this feature is controlling.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160216/0d0a3c78/attachment.html>


More information about the swift-evolution mailing list