[swift-evolution] Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall
Ilya Belenkiy
ilya.belenkiy at gmail.com
Tue Feb 16 08:34:08 CST 2016
+1. great original idea. I really like the improvements proposed by Howard.
On Mon, Feb 15, 2016 at 10:36 PM Howard Lovatt via swift-evolution <
swift-evolution at swift.org> wrote:
> Building on Haravikk's suggestion:
>
> 1. Make methods and classes final by default and mark an overridable
> class with `class(option)` or `class(replace)` (see below for
> `class(replace)`).
> 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.
> 3. A change from Haravikk'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`.)
> 4. Establish a hierarchy, since the override becomes part of the
> method's public signature, in particular:
> 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.)
> 4.b. `func/override(option)` can be overridden/implemented
> by `override(option)`, `override(option, before)`, `override(option,
> after)`, or `override(option, instead)`.
> 4.c. `func/override(before)`, `func/override(after)`, and
> `func/override(instead)` can only be overridden/implemented by the same
> modifier.
> 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.
> 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)`.)
> 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.
>
> EG:
>
> class(replace) Abstract { // Point 1: class marked as replace, it is
> therefore abstract and you can't call init. Point 6: it has an abstract
> method therefore must be abstract itself.
> func abstract() // Point 5: declare an abstract method (it has no
> body), equivalent to `func(replace)`.
>
> func(option) overridable() { // Point 2: declare an optionally
> overridable method. Point 3: same override semantics as Swift 2.
> print("Optionally overridable with any super call OK")
> }
>
> func finalFunc() { // Point 1: methods are final by default. Point
> 8: `func` is shorthand for `func(final)` when the method has a body.
> print("Method is final")
> }
> }
>
> class Final: Overridable { // Point 1: class is final since it isn't
> annotated.
> 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)`.
> print("Implementation of abstract method")
> }
>
> 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)`.
> print("Method is final because class is final")
> }
> }
>
> class(option) Derived: Overridable { // Point 1: class is overridable
> because it is annotated option.
> override(replace, after) abstract() { // Point 4.a: implementation
> of an abstract class
> print("In a derived class this will be printed after the
> derived class's body has finished")
> }
>
> override(option, final) overridable() { // Point 7: method is
> final because it is annotated final.
> print("Method is final because class is final")
> }
> }
>
>
> -- Howard.
>
> On 16 February 2016 at 09:56, Haravikk via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> Oh, it looks like Alexey beat me to a similar solution, but split the
>> thread (at least in Mail.app):
>>
>> On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> Hi
>>
>> I would like to suggest you to extend your proposal.
>>
>> In my practice, overriding super functions can have several semantics.
>> 1) Replace - simple case for abstract classes which implementation do
>> nothing, or throw an exceptions.
>> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc.
>> All cases where super expect to be called before child code.
>> 3) Before super - opposite to 2.
>> 4) Override - no rules about order, but super call must be done.
>>
>> So code can look like:
>>
>> override(after) func viewDidLoad() {
>> // super.viewDidLoad() <— no need to call super at first line.
>> // child code
>> }
>>
>> override(before) func tearDown() {
>> // clean code
>> // super… inserted by compiler
>> }
>>
>> override(instead) func loadView() {
>> // super.loadView() <— marked as an error with appropriate fix-up to
>> remove instead modifier
>> }
>>
>> override func refillHealthBar() {
>> // absent call to super will cause an error with fix-up to add
>> (instead) modifier
>> }
>>
>> I am not sure about exposing this in a public interface and limit child
>> override options.
>>
>> But in general - what is your thoughts about this approach to problem
>> that you mention?
>>
>>
>> On 15 Feb 2016, at 22:52, Haravikk via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> 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.
>>
>> 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:
>>
>> class View {
>> @super(required) func viewDidLoad() { … }
>> }
>>
>> class Button : View {
>> override func viewDidLoad() { … }
>> }
>>
>> class Widget : View {
>> override func viewDidLoad() {
>> super.viewDidLoad()
>> …
>> }
>> }
>>
>> 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.
>>
>> So the options for @super would be:
>>
>>
>> - *required: *child-class must call parent implementation of this
>> method.
>> - *optional:* default behaviour, child can choose whether to call the
>> parent’s method.
>> - *denied:* child may not call parent’s method (useful if it makes
>> assumptions that a child-class may not follow), but can still
>> extend/override.
>>
>>
>> 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.
>>
>> On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> Hi!
>>
>> 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).
>> 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:
>>
>> class View {
>> func viewDidLoad() {
>> // does something
>> }
>> }
>>
>> class Button: View {
>> override func viewDidLoad() {
>> super.viewDidLoad() // <— this might be forgotten
>> // do something other
>> }
>> }
>>
>> 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.
>>
>> // Example for extending a function
>> class Button: View {
>> extend func viewDidLoad() {
>> super.viewDidLoad()
>> // do something
>> }
>>
>> extend func viewDidAppear() {
>> // do something
>> } // <— the compiler should throw an error here.
>> }
>>
>> // Example for replacing a function
>> class Geometry {
>> func volume() -> Double {
>> return 0;
>> }
>> }
>>
>> class Cube: Geometry {
>> var length: Double = 0.0
>> replace func volume() -> Double {
>> let v = length * length * length
>> return v
>> }
>> }
>>
>> Cheers,
>> Florian
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160216/53a02080/attachment.html>
More information about the swift-evolution
mailing list