Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall

+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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I understand what you are talking about.
But point is not to limit available behaviors, but to give some hints to compiler and protect programmer from errors.

But this can be helpful in child classes. I mean, that programmer will define the semantic of overriding, and not the semantic of inheritance.

···

From my point of view, there is no need to specify order in super class.

I disagree with the introduction of a method to specify if super must be call first or last. Defining that super must be call is fine, but I don’t see why the operation order should be enforced.

If the super class declares a method overridable but require that some code must be perform first, it can simply execute that code before calling the overridable method instead of putting it in the super class definition then force the subclass to call super first.

Moreover, I’m not fond of declaring that requirement in the overriding classes. That is the superclass that should define if a super implementation is required, not the children classes.

> Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> Jean-Daniel: can you clarify which aspect you're disagreeing with?
>
> For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
> Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?
>
>
> On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> >
> > -1 for enforcing the super call place.
> > While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.
> >
> > I have some use cases that rely on performing setup before calling the super.viewDidLoad().
> >
> > >Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> > >
> > >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?
> > >
> > >
> > >>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@swift.org(mailto:swift-evolution@swift.org)
> > >https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution

Building on Haravikk's suggestion:

    1. Make methods and classes final by default

That's a serious problem for Swift resilience—it's not safe to change a public class from final to non-final because that would break devirtualized calls in other modules. Whatever the default is, it needs to not break things.

Overall, I don't like this proposal for several reasons:

- It conflates several different features—final, abstract, super call requirement, super call location—into a single set of annotations.
- It violates the usual grammar of Swift declarations by attaching particular modifiers directly to the keyword, disrupting the usual flow of modifiers-keyword-name-type.
- It not only supports, but actively encourages, placing extremely heavy constraints on subclass implementations. (Want to put a logging statement before a "before" method's super call or after an "after" method's? Too bad, the guy who wrote the superclass said "no".)

In general, this proposal seems like it's tremendously overengineered, insufficiently motivated, and fits poorly into Swift's syntax.

···

--
Brent Royal-Gordon
Architechies

Not that I disagree with having a superclass overly dictate what a subclass
can do... it can quickly become a double edges sword however it can be
powerful for complex class designs especially if they focus on extension
via subclassing.

It should be noted it isn't always possible to leverage the super class
calling a final method as a point of enforcement. If the interface is
public then any code could call an overridden function without the ability
for the super class to enforce desired requirements. (yeah you could likely
achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of its
super class chain, if no such function is found up the chain at compile
time then a compiler error can be omitted to help catch missed function
signature changes that affect a sub-class (or fat fingering of a function
name), if absent and an override is taking place the compiler could also
flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should
at some point call up to the supers implementation, if that isn't found the
compiler should provide a fixup to either add the (instead) qualifier to
make it clear you want to replace the supers implementation or force you to
add a call to super

override(before) & override(after) could exist to help catch errors and/or
generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the
class stating this requirement should be considered abstract

require(super) -> states that any override must call supers implementation
at some point in its body, override(instead) wouldn't be allowed, if the
requirement is not specified the subclass is free to call or not call the
supers implementation

require(superBefore) -> states that it is expected that a subclass calls
super before doing things in its override, if the subclass doesn't doesn't
honor this requirement the compiler will help to enforce it however a
subclass could state it is explicitly ignoring that requirement by say
something like override(ignoreBefore), override(instead) wouldn't be
allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a
base class to provide some amount of implementation while still being
considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this
but I see being a potential benefit for class authors.

-Shawn

···

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution < swift-evolution@swift.org> wrote:

Agreed - attempting to enforce the ordering is too fiddly and complicated,
IMO. If the superclass must ensure a specific order, then it should do so
itself by first calling a final function that then calls the overridable
function at the right time.

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

    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.

···

On 16 Feb 2016, at 03:36, Howard Lovatt <howard.lovatt@gmail.com> wrote:

A lot of the time Cocoa documentation says that you must override a method,
or must not, and if you do, whether to to it in the beginning, the end, or
at some point. This proposal would make it enforceable by the compiler.
With the right defaults, this could function exactly as what we have today
but give additional ways for the compiler to enforce and automate the
implementor's intent instead of relying on the documentation.

···

On Tue, Feb 16, 2016 at 10:00 AM Alexey Demedetskiy via swift-evolution < swift-evolution@swift.org> wrote:

I understand what you are talking about.
But point is not to limit available behaviors, but to give some hints to
compiler and protect programmer from errors.

From my point of view, there is no need to specify order in super class.
But this can be helpful in child classes. I mean, that programmer will
define the semantic of overriding, and not the semantic of inheritance.

> I disagree with the introduction of a method to specify if super must be
call first or last. Defining that super must be call is fine, but I don’t
see why the operation order should be enforced.
>
> If the super class declares a method overridable but require that some
code must be perform first, it can simply execute that code before calling
the overridable method instead of putting it in the super class definition
then force the subclass to call super first.
>
> Moreover, I’m not fond of declaring that requirement in the overriding
classes. That is the superclass that should define if a super
implementation is required, not the children classes.
>
>
> > Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> > Jean-Daniel: can you clarify which aspect you're disagreeing with?
> >
> > For example: should standard library types prefer the 'override' form
which enforces calling super but doesn't enforce when it is called?
> > Perhaps 'override(before)' should be an indication that, if the
overriding method doesn't explicitly declare the super call, then it should
be called implicitly at the start of the function?
> >
> >
> > On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > >
> > > -1 for enforcing the super call place.
> > > While we usually call super at the beginning of viewDidLoad for
instance, there is absolutely no need to enforce it and it may result in
problem when some work have to be done before the super method is executed.
> > >
> > > I have some use cases that rely on performing setup before calling
the super.viewDidLoad().
> > >
> > > >Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> > > >
> > > >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?
> > > >
> > > >
> > > >>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@swift.org(mailto:swift-evolution@swift.org)
> > > >https://lists.swift.org/mailman/listinfo/swift-evolution
> > >
> > > _______________________________________________
> > > swift-evolution mailing list
> > > swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> > > https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

My vote is for a simple `require(override)` or `require(super)` on the
super-class. The user should be free to choose where to call super if
needed where she/he wants.

Other thing that I think is related is to declare a func abstract
(something like `require(override)` but without body implementation).

-Van

···

On Tue, Feb 16, 2016 at 4:12 PM, Shawn Erickson via swift-evolution < swift-evolution@swift.org> wrote:

Not that I disagree with having a superclass overly dictate what a
subclass can do... it can quickly become a double edges sword however it
can be powerful for complex class designs especially if they focus on
extension via subclassing.

It should be noted it isn't always possible to leverage the super class
calling a final method as a point of enforcement. If the interface is
public then any code could call an overridden function without the ability
for the super class to enforce desired requirements. (yeah you could likely
achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of
its super class chain, if no such function is found up the chain at compile
time then a compiler error can be omitted to help catch missed function
signature changes that affect a sub-class (or fat fingering of a function
name), if absent and an override is taking place the compiler could also
flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should
at some point call up to the supers implementation, if that isn't found the
compiler should provide a fixup to either add the (instead) qualifier to
make it clear you want to replace the supers implementation or force you to
add a call to super

override(before) & override(after) could exist to help catch errors and/or
generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the
class stating this requirement should be considered abstract

require(super) -> states that any override must call supers implementation
at some point in its body, override(instead) wouldn't be allowed, if the
requirement is not specified the subclass is free to call or not call the
supers implementation

require(superBefore) -> states that it is expected that a subclass calls
super before doing things in its override, if the subclass doesn't doesn't
honor this requirement the compiler will help to enforce it however a
subclass could state it is explicitly ignoring that requirement by say
something like override(ignoreBefore), override(instead) wouldn't be
allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a
base class to provide some amount of implementation while still being
considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this
but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution < > swift-evolution@swift.org> wrote:

Agreed - attempting to enforce the ordering is too fiddly and
complicated, IMO. If the superclass must ensure a specific order, then it
should do so itself by first calling a final function that then calls the
overridable function at the right time.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

There are some cases where a predefined place to call super is very useful
and can be automated. One such example is dealloc in ObjC or deinit in
Swift. And the compiler already does this automatically. The proposal would
make this more generic. I expect that if it's implemented, the place to
call super will not be specified most of the time. But occasionally, it
might be very useful and reduce human error.

···

On Tue, Feb 16, 2016 at 2:24 PM Vanderlei Martinelli via swift-evolution < swift-evolution@swift.org> wrote:

My vote is for a simple `require(override)` or `require(super)` on the
super-class. The user should be free to choose where to call super if
needed where she/he wants.

Other thing that I think is related is to declare a func abstract
(something like `require(override)` but without body implementation).

-Van

On Tue, Feb 16, 2016 at 4:12 PM, Shawn Erickson via swift-evolution < > swift-evolution@swift.org> wrote:

Not that I disagree with having a superclass overly dictate what a
subclass can do... it can quickly become a double edges sword however it
can be powerful for complex class designs especially if they focus on
extension via subclassing.

It should be noted it isn't always possible to leverage the super class
calling a final method as a point of enforcement. If the interface is
public then any code could call an overridden function without the ability
for the super class to enforce desired requirements. (yeah you could likely
achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of
its super class chain, if no such function is found up the chain at compile
time then a compiler error can be omitted to help catch missed function
signature changes that affect a sub-class (or fat fingering of a function
name), if absent and an override is taking place the compiler could also
flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should
at some point call up to the supers implementation, if that isn't found the
compiler should provide a fixup to either add the (instead) qualifier to
make it clear you want to replace the supers implementation or force you to
add a call to super

override(before) & override(after) could exist to help catch errors
and/or generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the
class stating this requirement should be considered abstract

require(super) -> states that any override must call supers
implementation at some point in its body, override(instead) wouldn't be
allowed, if the requirement is not specified the subclass is free to call
or not call the supers implementation

require(superBefore) -> states that it is expected that a subclass calls
super before doing things in its override, if the subclass doesn't doesn't
honor this requirement the compiler will help to enforce it however a
subclass could state it is explicitly ignoring that requirement by say
something like override(ignoreBefore), override(instead) wouldn't be
allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a
base class to provide some amount of implementation while still being
considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this
but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution < >> swift-evolution@swift.org> wrote:

Agreed - attempting to enforce the ordering is too fiddly and
complicated, IMO. If the superclass must ensure a specific order, then it
should do so itself by first calling a final function that then calls the
overridable function at the right time.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

The addition of before and after are just icing on the cake as they say (I
see benefit but am not sure about them being worth it). I agree the core
benefit would come from being able to state "require override" as a base
class with or without providing an implementation. The only hole I see in
that is how to help subclassers detected missed calls to super (subclass
override(instead) helps deal with that well enough). I could see require
(override) and require (override,super) as base class if the author
strongly feels a subclass needs to involve the supers implementation... of
course then you get back to the edge case of before and after.

So at it core I support...

For base classes require(override) with or without an implementation,
without implies abstract, with implies a subclass should likely call the
base implementation in its override

For subclasses override to detect override attempts or on omission flag
unexpected overrides, override(instead) to state it is ok that supers
implementation isn't called in the override (assumed to be desired unless
instead is stated).

···

On Tue, Feb 16, 2016 at 11:24 AM Vanderlei Martinelli < vmartinelli@alecrim.com> wrote:

My vote is for a simple `require(override)` or `require(super)` on the
super-class. The user should be free to choose where to call super if
needed where she/he wants.

Other thing that I think is related is to declare a func abstract
(something like `require(override)` but without body implementation).

-Van

On Tue, Feb 16, 2016 at 4:12 PM, Shawn Erickson via swift-evolution < > swift-evolution@swift.org> wrote:

Not that I disagree with having a superclass overly dictate what a
subclass can do... it can quickly become a double edges sword however it
can be powerful for complex class designs especially if they focus on
extension via subclassing.

It should be noted it isn't always possible to leverage the super class
calling a final method as a point of enforcement. If the interface is
public then any code could call an overridden function without the ability
for the super class to enforce desired requirements. (yeah you could likely
achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of
its super class chain, if no such function is found up the chain at compile
time then a compiler error can be omitted to help catch missed function
signature changes that affect a sub-class (or fat fingering of a function
name), if absent and an override is taking place the compiler could also
flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should
at some point call up to the supers implementation, if that isn't found the
compiler should provide a fixup to either add the (instead) qualifier to
make it clear you want to replace the supers implementation or force you to
add a call to super

override(before) & override(after) could exist to help catch errors
and/or generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the
class stating this requirement should be considered abstract

require(super) -> states that any override must call supers
implementation at some point in its body, override(instead) wouldn't be
allowed, if the requirement is not specified the subclass is free to call
or not call the supers implementation

require(superBefore) -> states that it is expected that a subclass calls
super before doing things in its override, if the subclass doesn't doesn't
honor this requirement the compiler will help to enforce it however a
subclass could state it is explicitly ignoring that requirement by say
something like override(ignoreBefore), override(instead) wouldn't be
allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a
base class to provide some amount of implementation while still being
considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this
but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution < >> swift-evolution@swift.org> wrote:

Agreed - attempting to enforce the ordering is too fiddly and
complicated, IMO. If the superclass must ensure a specific order, then it
should do so itself by first calling a final function that then calls the
overridable function at the right time.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Yes, that is the kind of things that do get a big +1 from me ;).

···

Sent from my iPhone

On 16 Feb 2016, at 16:20, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

A lot of the time Cocoa documentation says that you must override a method, or must not, and if you do, whether to to it in the beginning, the end, or at some point. This proposal would make it enforceable by the compiler. With the right defaults, this could function exactly as what we have today but give additional ways for the compiler to enforce and automate the implementor's intent instead of relying on the documentation.
On Tue, Feb 16, 2016 at 10:00 AM Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org> wrote:

I understand what you are talking about.
But point is not to limit available behaviors, but to give some hints to compiler and protect programmer from errors.

From my point of view, there is no need to specify order in super class.
But this can be helpful in child classes. I mean, that programmer will define the semantic of overriding, and not the semantic of inheritance.

> I disagree with the introduction of a method to specify if super must be call first or last. Defining that super must be call is fine, but I don’t see why the operation order should be enforced.
>
> If the super class declares a method overridable but require that some code must be perform first, it can simply execute that code before calling the overridable method instead of putting it in the super class definition then force the subclass to call super first.
>
> Moreover, I’m not fond of declaring that requirement in the overriding classes. That is the superclass that should define if a super implementation is required, not the children classes.
>
>
> > Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> > Jean-Daniel: can you clarify which aspect you're disagreeing with?
> >
> > For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
> > Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?
> >
> >
> > On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > >
> > > -1 for enforcing the super call place.
> > > While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.
> > >
> > > I have some use cases that rely on performing setup before calling the super.viewDidLoad().
> > >
> > > >Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>a écrit :
> > > >
> > > >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?
> > > >
> > > >
> > > >>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@swift.org(mailto:swift-evolution@swift.org)
> > > >https://lists.swift.org/mailman/listinfo/swift-evolution
> > >
> > > _______________________________________________
> > > swift-evolution mailing list
> > > swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> > > https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think it should be possible to enforce a convention. Sub classing does come with limitations in order to work well and if you are subclassing something you have no code access to you are relying only on documentation to give you hints on what to do. I think we should give the author the ability to make it explicit in this case.

···

Sent from my iPhone

On 16 Feb 2016, at 19:24, Vanderlei Martinelli via swift-evolution <swift-evolution@swift.org> wrote:

My vote is for a simple `require(override)` or `require(super)` on the super-class. The user should be free to choose where to call super if needed where she/he wants.

Other thing that I think is related is to declare a func abstract (something like `require(override)` but without body implementation).

-Van

On Tue, Feb 16, 2016 at 4:12 PM, Shawn Erickson via swift-evolution <swift-evolution@swift.org> wrote:
Not that I disagree with having a superclass overly dictate what a subclass can do... it can quickly become a double edges sword however it can be powerful for complex class designs especially if they focus on extension via subclassing.

It should be noted it isn't always possible to leverage the super class calling a final method as a point of enforcement. If the interface is public then any code could call an overridden function without the ability for the super class to enforce desired requirements. (yeah you could likely achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of its super class chain, if no such function is found up the chain at compile time then a compiler error can be omitted to help catch missed function signature changes that affect a sub-class (or fat fingering of a function name), if absent and an override is taking place the compiler could also flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should at some point call up to the supers implementation, if that isn't found the compiler should provide a fixup to either add the (instead) qualifier to make it clear you want to replace the supers implementation or force you to add a call to super

override(before) & override(after) could exist to help catch errors and/or generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the class stating this requirement should be considered abstract

require(super) -> states that any override must call supers implementation at some point in its body, override(instead) wouldn't be allowed, if the requirement is not specified the subclass is free to call or not call the supers implementation

require(superBefore) -> states that it is expected that a subclass calls super before doing things in its override, if the subclass doesn't doesn't honor this requirement the compiler will help to enforce it however a subclass could state it is explicitly ignoring that requirement by say something like override(ignoreBefore), override(instead) wouldn't be allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a base class to provide some amount of implementation while still being considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:
Agreed - attempting to enforce the ordering is too fiddly and complicated, IMO. If the superclass must ensure a specific order, then it should do so itself by first calling a final function that then calls the overridable function at the right time.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

For me this solution sounds exactly for what i was looking for. I don’t know if the superclass should be able to dictate when the supers implementation has to be called but it should be able to dictate, that supers implementation must be called. So currently this is my preferred solution:

For subcasses:
override func foo() {} // super must be called somewhere inside the body
override(before) func foo() {} // semantic hint, super must not be called inside the body, the compiler generates the code before the body
override(after) func foo() {} // semantic hint, super must not be called inside the body, the compiler generates the code after the body
override(instead) func foo() {} // replaces supers implementation, super must not be called inside the body

For superclasses:
func foo() {} // subclass can override and may or may not call supers implementation
require(override) func foo() // subclass must override and must not call supers implementation (which doesn’t exist)
require(override) func foo() {} // subclass must override and may or may not call supers implementation
require(override, super) // subclass must override and must call supers implementation

Cheers, Florian

···

Am 16.02.2016 um 19:12 schrieb Shawn Erickson via swift-evolution <swift-evolution@swift.org>:

Not that I disagree with having a superclass overly dictate what a subclass can do... it can quickly become a double edges sword however it can be powerful for complex class designs especially if they focus on extension via subclassing.

It should be noted it isn't always possible to leverage the super class calling a final method as a point of enforcement. If the interface is public then any code could call an overridden function without the ability for the super class to enforce desired requirements. (yeah you could likely achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of its super class chain, if no such function is found up the chain at compile time then a compiler error can be omitted to help catch missed function signature changes that affect a sub-class (or fat fingering of a function name), if absent and an override is taking place the compiler could also flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should at some point call up to the supers implementation, if that isn't found the compiler should provide a fixup to either add the (instead) qualifier to make it clear you want to replace the supers implementation or force you to add a call to super

override(before) & override(after) could exist to help catch errors and/or generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the class stating this requirement should be considered abstract

require(super) -> states that any override must call supers implementation at some point in its body, override(instead) wouldn't be allowed, if the requirement is not specified the subclass is free to call or not call the supers implementation

require(superBefore) -> states that it is expected that a subclass calls super before doing things in its override, if the subclass doesn't doesn't honor this requirement the compiler will help to enforce it however a subclass could state it is explicitly ignoring that requirement by say something like override(ignoreBefore), override(instead) wouldn't be allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a base class to provide some amount of implementation while still being considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:
Agreed - attempting to enforce the ordering is too fiddly and complicated, IMO. If the superclass must ensure a specific order, then it should do so itself by first calling a final function that then calls the overridable function at the right time.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m sorry, I don’t believe this. How can the implementor of the superclass possibly know whether the arbitrary code that the implementor of a subclass can write should go before, after or around the call to the super implementation? It’s nonsense.

Furthermore, I don’t believe that the implementor of the super class can foresee all the possible cases of subclass implementation so it would be foolish to try to even enforce a call to super at any point.

Then there are the implementation problems. The attribute would restrict the subclass implementor to calling the super implementation in the implementation of the subclass function. They couldn’t call out to a private method to call the super implementation. They couldn’t put it inside a loop or control structure unless the compiler can definitely prove that the code path is executed.

How do you deal with multi-level hierarchies? Do you enforce adding the attribute to the method in the intermediate class?

I think the whole idea of the compiler enforcing calls to super for non initialisers is misconceived. There will be enough edge cases and implementation issues to have subclass implementors cursing it. We should just accept the fact that we can’t legislate every bug out of existence and live things as they are.

···

On 16 Feb 2016, at 17:20, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

A lot of the time Cocoa documentation says that you must override a method, or must not, and if you do, whether to to it in the beginning, the end, or at some point.

@Haravikk,

I am not perticularly fussed about the exact syntax so long as it is clear
and consistent, it is the semantics I am most interested in. I would say
just go with what is the most popular syntax. The syntax I suggested is
clear, consistent, and concise, that is why I suggested it, EG instead of:

    @super(option) override func name() { ... }

I am suggesting

    override(option) name() { ... }

Its only syntax :). Either is fine because they are both clear and
consistent.

Changing tack to abstract methods and classes. Maybe it is necessary to
propose abstract methods and classes for Swift with a future expansion
section noting that it is the intention to add control over when super is
called at a later date and giving some examples. That way abstract classes
can be added with systax that can be extended to accommodate more control
at a later date. The problem with doing two seperate proposals is that the
syntax could become inconsistent.

Thanks for starting this thread, I think it would be a valuable addition to
Swift.

-- Howard.

···

On Wednesday, 17 February 2016, Haravikk <swift-evolution@haravikk.me> wrote:

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

On 16 Feb 2016, at 03:36, Howard Lovatt <howard.lovatt@gmail.com > <javascript:_e(%7B%7D,'cvml','howard.lovatt@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.

--
-- Howard.

Comments in-line below.

  -- Howard.

> Building on Haravikk's suggestion:
>
> 1. Make methods and classes final by default

That's a serious problem for Swift resilience—it's not safe to change a
public class from final to non-final because that would break devirtualized
calls in other modules. Whatever the default is, it needs to not break
things.

If a class/method is final it can be made virtual, but not vice versa.
Therefore the default is best as final since you can change your mind
later. Whereas a virtual declaration you are stuck with.

Overall, I don't like this proposal for several reasons:

- It conflates several different features—final, abstract, super call
requirement, super call location—into a single set of annotations.

Yes. There is some discussion of splitting out abstract. Could also split
out final. However you wouldn't want a solution for final or abstract that
stopped you from later adding super constraints if people decided they were
still useful.

- It violates the usual grammar of Swift declarations by attaching
particular modifiers directly to the keyword, disrupting the usual flow of
modifiers-keyword-name-type.

Different syntaxes have been discussed, mainly `@super(option) override
func name()` and `override(option) name()`, both have precedence in Swift,
e.g. annotations like `@noexcape` and options on annotations and
constraints on visibility like `private(set)` respectively.

- It not only supports, but actively encourages, placing extremely heavy
constraints on subclass implementations. (Want to put a logging statement
before a "before" method's super call or after an "after" method's? Too
bad, the guy who wrote the superclass said "no".)

A similar discussion has occurred re. pure functions. It might be possible
to say no mutating stored properties before/after the super call in a
"before"/"after" method respectively. This would require some careful
consideration though.

In general, this proposal seems like it's tremendously overengineered,
insufficiently motivated, and fits poorly into Swift's syntax.

Not the first time this sort of discussion has come up on Swift Evolution -
therefore there is some interest.

···

On 17 February 2016 at 12:22, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies

That's a serious problem for Swift resilience—it's not safe to change a public class from final to non-final because that would break devirtualized calls in other modules. Whatever the default is, it needs to not break things.

Swift hasn’t really shied away from breaking things thus far, but this is partly why I mentioned supporting a class level override. So for example, if @super(optional) is the current behaviour (can override, compiler doesn’t care what you do) then that could be added to all existing classes in a project, but without it a new class will default to its methods being final.

- It conflates several different features—final, abstract, super call requirement, super call location—into a single set of annotations.

Not quite; I’d say that abstract is kind of its own thing, but would definitely build in the addition of extension requirements. Regarding the rest, is them being in a single set of annotations actually a bad thing? IMO that’s an advantage, as plus it’s not like it should be complicated. In the sample set of annotations I gave you might do:

  @super(optional, before)

Which essentially reads as “extending classes don’t need to include super call, but must place it first if they do”. The most major change is really that the final keyword wouldn’t be necessary except for classes that set @super(optional) as their default (as everything would be overridable otherwise). That said it probably does make sense to just make final another type of requirement for consistency in that case.

- It violates the usual grammar of Swift declarations by attaching particular modifiers directly to the keyword, disrupting the usual flow of modifiers-keyword-name-type.

private(set) already does this, so super(optional, before) or whatever wouldn’t be any different. We’re considering other options like @attributes as well, but they’re functionally the same so it really comes down to code style.

- It not only supports, but actively encourages, placing extremely heavy constraints on subclass implementations. (Want to put a logging statement before a "before" method's super call or after an "after" method's? Too bad, the guy who wrote the superclass said "no”.)

I wouldn’t say it encourages heavy constraints, in fact I’d expect most developers to mostly use required or optional. The before and after conditions make more sense in the case of abstract classes that are partial implementations specifically intended to be built upon in a certain way.

It’s possible the restriction could be relaxed to allow non-mutating operations before/after the required statement, but I think in general developers shouldn’t be adding the before/after requirements unless they’re absolutely certain it has to be done that way. Technical you can still work around it like so:

  class Foo {
    super(before) func doSomething() { … }
  }
  class Bar : Foo {
    super(required) override func doSomething() {
      super.doSomething(); // Foo decreed that this shall be so
      …
    }
  }
  class AddLogging : Bar {
    override func doSomething() {
      /* Do some logging here and there’s nothing Foo can do about it */
      super.doSomething()
    }
  }

Not pretty I know, but the point is that you aren’t actually completely prevented, but you should have a good reason to want to do this if it circumvents what a developer set as an explicit requirement. In the case of Foo being abstract however this actually makes a lot of sense, as Bar would be the first proper implementation, so has to follow all the rules, but relaxing them afterwards is fine.

In general, this proposal seems like it's tremendously overengineered, insufficiently motivated, and fits poorly into Swift's syntax.

I don’t think the guts are actually that complex, the syntax just needs to be paired down to basics, and abstract classes possibly added later once the groundwork is done.

···

On 17 Feb 2016, at 01:22, Brent Royal-Gordon <brent@architechies.com> wrote:

One thing i forgot is
For superclasses:
require(super) func foo() {} // subclass may override but if it must call supers implementation.

Another thing i’m wondering is, how it would look like if a subclass overrides supers function and defines it’s own function to be required to be called from subclasses?

require(super) override(before) func foo() {}

Florian

···

Am 16.02.2016 um 21:39 schrieb Florian Liefers via swift-evolution <swift-evolution@swift.org>:

For me this solution sounds exactly for what i was looking for. I don’t know if the superclass should be able to dictate when the supers implementation has to be called but it should be able to dictate, that supers implementation must be called. So currently this is my preferred solution:

For subcasses:
override func foo() {} // super must be called somewhere inside the body
override(before) func foo() {} // semantic hint, super must not be called inside the body, the compiler generates the code before the body
override(after) func foo() {} // semantic hint, super must not be called inside the body, the compiler generates the code after the body
override(instead) func foo() {} // replaces supers implementation, super must not be called inside the body

For superclasses:
func foo() {} // subclass can override and may or may not call supers implementation
require(override) func foo() // subclass must override and must not call supers implementation (which doesn’t exist)
require(override) func foo() {} // subclass must override and may or may not call supers implementation
require(override, super) // subclass must override and must call supers implementation

Cheers, Florian

Am 16.02.2016 um 19:12 schrieb Shawn Erickson via swift-evolution <swift-evolution@swift.org>:

Not that I disagree with having a superclass overly dictate what a subclass can do... it can quickly become a double edges sword however it can be powerful for complex class designs especially if they focus on extension via subclassing.

It should be noted it isn't always possible to leverage the super class calling a final method as a point of enforcement. If the interface is public then any code could call an overridden function without the ability for the super class to enforce desired requirements. (yeah you could likely achieve this by having the overridables have non-public access)

Anyway some more thinking out loud...

sub-class:

override -> implies that the subclass intends to override a function of its super class chain, if no such function is found up the chain at compile time then a compiler error can be omitted to help catch missed function signature changes that affect a sub-class (or fat fingering of a function name), if absent and an override is taking place the compiler could also flag unexpected override (e.g. function signature collision).

override with no qualifier is assumed to imply the overriding code should at some point call up to the supers implementation, if that isn't found the compiler should provide a fixup to either add the (instead) qualifier to make it clear you want to replace the supers implementation or force you to add a call to super

override(before) & override(after) could exist to help catch errors and/or generate code as needed (super call not needed in the overriding)

override func foo() {...}
override(instead|before|after) func bar() {...}

super-class:

require -> implies some requirement for those subclassing the function

require(override) -> implies that a subclass must override and that the class stating this requirement should be considered abstract

require(super) -> states that any override must call supers implementation at some point in its body, override(instead) wouldn't be allowed, if the requirement is not specified the subclass is free to call or not call the supers implementation

require(superBefore) -> states that it is expected that a subclass calls super before doing things in its override, if the subclass doesn't doesn't honor this requirement the compiler will help to enforce it however a subclass could state it is explicitly ignoring that requirement by say something like override(ignoreBefore), override(instead) wouldn't be allowed, consider this an escape hatch for subclasses,

require(superAfter) -> same as above but after the override body

Note something like require(override, superXxx) is valid allowing for a base class to provide some amount of implementation while still being considered an abstract class.

final func baz() {...}
require(override) func foo() {}
require(override, super|superBefore|superAfter) func bar() {...}

Note I have not convinced myself of the true need for something like this but I see being a potential benefit for class authors.

-Shawn

On Tue, Feb 16, 2016 at 6:51 AM Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:
Agreed - attempting to enforce the ordering is too fiddly and complicated, IMO. If the superclass must ensure a specific order, then it should do so itself by first calling a final function that then calls the overridable function at the right time.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m sorry, I don’t believe this. How can the implementor of the superclass possibly know whether the arbitrary code that the implementor of a subclass can write should go before, after or around the call to the super implementation? It’s nonsense.

The before and after clauses probably wouldn’t be the most commonly used except in cases where the developer is very sure that they are needed. I think they’d be used more by abstract classes than regular ones, where a partial implementation needs to be completed in a particular way, required and optional would be the most commonly used I think.

They couldn’t call out to a private method to call the super implementation.

What do you hope to gain by doing so? If the parent method requires that it is called then it has to called in all paths the sub-class implementation can take. You can still outsource work to a private method, you can even still make a decision based on what the private method’s results are, so long as you call the super method in every case.

They couldn’t put it inside a loop or control structure unless the compiler can definitely prove that the code path is executed.

Why would you want to potentially call the super-method zero or many times when your child method is only called once? I’d also say that this is exactly what required should prevent, as there should be no uncertainty over it being called, since the parent method specifically forbids it.

It shouldn’t prevent the use of a conditional, so long as all paths call the super method, i.e:

  if someCondition {
    …
    super.doSomething()
  } else {
    super.doSomething()
    …
  }

Would be fine (both branches call the super method) but a conditional where super is only called in some branches, and nowhere else, is exactly what required is for. You actually raise an interesting question of whether it should be possible to call the super method more than once, that might be a possibility for another requirement, as in most cases it won’t make sense to call it more than once; for example, if you’re extending an add() method then potentially calling super.add() more than once seems like it could lead to unexpected results, and could be an error. For example:

  if someCondition {
    …
    super.doSomething()
  }

  …
  super.doSomething()

Could be a bug where the developer has forgotten to remove the conditional super call; if the parent class knows its method shouldn’t be called more than once per child call then it could prevent this.

How do you deal with multi-level hierarchies? Do you enforce adding the attribute to the method in the intermediate class?

It’s up to the developer of the sub-class. As proposed all methods would be final by default, including those overriding a method in a super class, so they would need their own requirements set in order for them to be overridable in the first place.

For example:

  class MyClass {
    @super(require)
    func someMethod() { … }

    @super(require)
    func someOtherMethod() { … }
  }

  class MySubClass : MyClass {
    @super(require)
    override func someMethod() { … } // Can be extended further

    override func someOtherMethod() { … } // Cannot be extended further
  }

There will be enough edge cases and implementation issues to have subclass implementors cursing it.

Only if the developer of the parent class is over zealous in their choice of restrictions, but you could say the same thing about a bunch of features, like developers who mark almost everything private; like I say, the before and after requirements shouldn’t be very common, while the rest are pretty straightforward. In most cases you’ll either be extending a class that was designed for that purpose, in which case the requirements should be set correctly, or you will be extending a class in your own code base, so can request a change to the requirements (or change them yourself).

···

On 17 Feb 2016, at 08:06, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote: