Add code to super methods.

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name ;-) has been requested several

times, but never got the momentum it deserves.

Considering the current confusion (especially in UIKit), it would be
really nice to have some help from the compiler, and I wonder how
composition and protocols would be helpful here at all.

As an intermediary measure, this seems like an interesting QoI
improvement for the compiler: warn when super.foo() is not called in
the overridden method.

Please no. Methods that need to be called when they are overridden are
almost always a result of poor design.

   “I don't always do Object Oriented Programming, but when I do, I use
   the Template Method Pattern"

understating-the-case-ly yrs,

I agree, that’s why I’m suggesting it be a ObjC-side attribute for use by e.g. UIKit. Regardless of how both of us may feel about UIKit’s design, it is the largest platform on which apps are made and there’s a chance for the compiler to enhance the developer experience. I do agree that we should be careful about condoning the practice for new/Swift-only frameworks.

···

On Nov 28, 2016, at 7:22 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Thu Nov 24 2016, Michael Ilseman <swift-evolution@swift.org> wrote:

On Nov 17, 2016, at 2:54 AM, Tino Heth via swift-evolution >> <swift-evolution@swift.org> wrote:

--
-Dave

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

Methods that need to be called when they are overridden are
almost always a result of poor design.

Without an explanation or data to back this statement, it's hard to argue about it, and I won't make random shots.

But as a matter of fact, we have to deal with methods which require the behaviour in question now, and I have no idea when Cocoa will be replaced with something better.

Just out of sheer curiosity:
What would be a better design for a method like viewWillAppear? The obvious alternative that is possible with current Swift and template methods looks really ugly to me:
Not only would you have to add two empty methods to each subclass of UIViewController, but also rely on that those methods are only overridden once in the hierarchy of inheritance.

If you must enforce that a subclass override calls its super implementation, you could enforce this via the type system, by creating a token type that only the super implementation is able to construct:

open class Base {
  public struct SuperFoo {
    // Only the super implementation can create SuperFoos.
    fileprivate init() {}
  }

  open func foo() -> SuperFoo {
    doBaseStuff()
    return SuperFoo()
  }
}

// In another file...

class Derived: Base {
  override func foo() -> SuperFoo {
    // Must call super to get a SuperFoo that lets us out of the function
    let result = super.foo()
    doDerivedStuff()
    return result
  }
}

-Joe

···

On Nov 28, 2016, at 7:22 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Nov 24 2016, Michael Ilseman <swift-evolution@swift.org> wrote:

On Nov 17, 2016, at 2:54 AM, Tino Heth via swift-evolution >> <swift-evolution@swift.org> wrote:

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name ;-) has been requested several

times, but never got the momentum it deserves.

Considering the current confusion (especially in UIKit), it would be
really nice to have some help from the compiler, and I wonder how
composition and protocols would be helpful here at all.

As an intermediary measure, this seems like an interesting QoI
improvement for the compiler: warn when super.foo() is not called in
the overridden method.

Please no. Methods that need to be called when they are overridden are
almost always a result of poor design.

   “I don't always do Object Oriented Programming, but when I do, I use
   the Template Method Pattern"

understating-the-case-ly y'rs,

I think I covered that, though it's a bit of a tricky situation; ideally a restriction shouldn't cause either of those print statements to cause an error, as they have no side-effects to self. The problem is detecting that, as we don't currently have any exposure of pure functions, and no way of knowing that a method of a reference type is mutating or non-mutating yet. I've raised it mainly for discussion as I'm not 100% sure of what we'd need to make it work.

If it isn't possible just yet though then the before and after attributes could always be delayed until later when non-mutating reference methods and pure functions can be reliably accounted for. This means that an initial release would be for the required, optional and never attributes to determine whether super has to be called, and error/warning to tweak the severity of that restriction.

I do still like the idea of allowing sub-class developers to use override(before) and override(after) to generate the super call for them regardless; while it may seem minor it allows you to focus in on what you're changing, but does have the slight added advantage of being its own scope, i.e- since you mentioned defer before, in an override(after) method the defer would be called before the automatic super method.

···

On 20 Nov 2016, at 16:00, Tino Heth <2th@gmx.de> wrote:

I'm not sure I follow your meaning on omission; I quite like Sean's suggestion of having an override(before) or override(final) in the sub-class, this way the call is explicitly auto-generated. I think having it be added automatically in the regular override case could be a bit confusing, I think a warning or error is better in that case as it should be visible so you know exactly when it is being called, the other cases don't need it (as they have the extra information on the override).

It's always possible to construct examples where there order is important, but I guess those won't matter in real code — and it would feel very strange to me if one of the print-statements would cause an error:
override func f(input: Int) {
  print("Before")
  super.f(input: input)
  print("After")
}

(even commands after a return statement compile just fine…)

1) Unless you know exactly what a subclass should do, you can not make assumptions about when a subclass should call its super implementation.

afaics, the majority agrees on this

2) I think it would be desirable if the default behavior is that a subclass is expected to call super in methods it overrides, not doing so should be a compile warning. This will be the general case, and I think it should be the default behavior.

I've been a fan of this since the first "all methods should be final" debate (imho it's a good compromise), but now the situation is more complicated because of the the differentiation of same-module overrides vs. external subclasses (after all, this feature could be modelled as yet another access level: public < open < "replaceable")

3) I think you should be able to silence that warning somehow. I am thinking something like:
override! func setFrame(...) { // note the ! at the end of override
   // not calling super
}

That was my favourite for overriding of methods that are neither final nor open. Imho the link between the "!" and the omission of the super-call isn't that intuitive, but as it is reused in 5), I'd view it as a general indicator for "I know what I'm doing".

4) There should be a macro / swift keyword that specifies that there is no need to call super. Something like @discardableFunc would be close to the existing @discardableResult annotation in Swift 3. This should be added to all functions where the default implementation is empty or unimportant etc.

This is coupled with 2) — but imho there should be a name/keyword for each option, no matter which one is default, so that discussion can be split into two parts ("how should it be called?", "what should be default?")

5) There should be a macro / swift keyword that specifies that the subclass is not allowed to call the super implementation. @deposedFunc? A native English speaker can properly come up with a better name. There are a few cases where this is relevant; NSOperations start() function is not allowed to call super. Using this keyword should make it a warning to call super and again I imagine that should also be silenced by using override! in case you are forced to call super anyway for some reason.

+1

Afaics, inheritance hasn't been covered yet, but the rules should be simple:
Making the call to super mandatory should always be possible, only the opposite would be problematic.

A full-fledged proposal imho should also include a paragraph about "interception":
override func foo(input: String) {
  super.foo(input + " bar")
}

override func bar() {
  if condition {
    super.bar()
  }
}

I wouldn't want to forbid either case, but they add a small amount of danger (compared to neutral monitoring), so it should be justified.

- Tino

Methods that need to be called when they are overridden are
almost always a result of poor design.

Without an explanation or data to back this statement, it's hard to argue about it, and I won't make random shots.

But as a matter of fact, we have to deal with methods which require the behaviour in question now, and I have no idea when Cocoa will be replaced with something better.

That's a great point. I just don't want to punish those who create methods with default implementations that are designed to be completely replaced in subclasses. I suppose that *could* encourage more use of protocols, but that seems like a very unfriendly way to reach a protocol-oriented utopia ;-)

Just out of sheer curiosity:
What would be a better design for a method like viewWillAppear? The obvious alternative that is possible with current Swift and template methods looks really ugly to me:
Not only would you have to add two empty methods to each subclass of UIViewController,

Why two, and why empty? UIViewController would supply its own empty default implementation.

but also rely on that those methods are only overridden once in the hierarchy of inheritance.

There's no law saying you *can't* call super if you absolutely must build a two-level hierarchy below UIViewController (though there are ways around that—the main one being to avoid inheritance hierarchies). I just don't want to create a world where you're always expected to call super everywhere, which is what would happen if we always warn when you don't call super.

···

On Nov 29, 2016, at 1:48 AM, Tino Heth <2th@gmx.de> wrote:

Why two, and why empty? UIViewController would supply its own empty default implementation.

The before/after pair: viewWillAppear would need a call to "subclassViewWillAppear" (which would be empty in the declaring class, and need a subsubclassViewWillAppear where it is overriden…) — and the same with viewDidAppear.
For properties, Swift has a special mechanism that saves us from the need to come up with names for new extension points (willSet/didSet), but there is no equivalent for regular methods.
I'm not propagating the use of long inheritance chains, but a language imho shouldn't try to educate its users by making it hard to use a paradigm it claims to support.

There's no law saying you *can't* call super if you absolutely must build a two-level hierarchy below UIViewController (though there are ways around that—the main one being to avoid inheritance hierarchies). I just don't want to create a world where you're always expected to call super everywhere, which is what would happen if we always warn when you don't call super.

I'm skeptical on adding more restrictions as well, so I guess I'd be fine with "you have to call super" as opt-in. After all, it is less restrictive than declaring everything final (which is a tiny bit safer, but much more limiting).
But afaics, no one has empirical data on how often each case (must call super, must not call super, do as you like) happens...

While I agree with most of your points Dave, I think forgetting to call super is very much a (hard to debug) real world problem today. Especially new developers seems unsure or likely to forget to call super when it is required.

I think my point is this; When you subclass code you have not written yourself you have no idea if the class you are subclassing is "poorly designed" and you should call super somewhere in your documentation. You can make assumptions, read the documentation or use trial and error, but there is no way to be certain unless the documentation is specific about it.

I went over the documentation for UIViewController. Is contains:
- 11 functions that specify that your subclass must call super during the implementation.
- 2 functions where the documentation specifies the default implementation is empty.
- 2 functions where you must not call super.
- 8 functions where you properly want to call super.
- 23 functions where I think there is no need to call super.

Based on the above I will admit that the default behaviour should properly be what we have today, but it would be lovely to have compiler warnings for the 11 functions that require it and the 2 functions where we should not call super.

···

On 29 Nov 2016, at 16.05, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 29, 2016, at 1:48 AM, Tino Heth <2th@gmx.de <mailto:2th@gmx.de>> wrote:

Methods that need to be called when they are overridden are
almost always a result of poor design.

Without an explanation or data to back this statement, it's hard to argue about it, and I won't make random shots.

But as a matter of fact, we have to deal with methods which require the behaviour in question now, and I have no idea when Cocoa will be replaced with something better.

That's a great point. I just don't want to punish those who create methods with default implementations that are designed to be completely replaced in subclasses. I suppose that *could* encourage more use of protocols, but that seems like a very unfriendly way to reach a protocol-oriented utopia ;-)

Just out of sheer curiosity:
What would be a better design for a method like viewWillAppear? The obvious alternative that is possible with current Swift and template methods looks really ugly to me:
Not only would you have to add two empty methods to each subclass of UIViewController,

Why two, and why empty? UIViewController would supply its own empty default implementation.

but also rely on that those methods are only overridden once in the hierarchy of inheritance.

There's no law saying you *can't* call super if you absolutely must build a two-level hierarchy below UIViewController (though there are ways around that—the main one being to avoid inheritance hierarchies). I just don't want to create a world where you're always expected to call super everywhere, which is what would happen if we always warn when you don't call super.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

While I agree with most of your points Dave, I think forgetting to call super is very much a (hard to debug) real world problem today. Especially new developers seems unsure or likely to forget to call super when it is required.

I think my point is this; When you subclass code you have not written yourself you have no idea if the class you are subclassing is "poorly designed" and you should call super somewhere in your documentation. You can make assumptions, read the documentation or use trial and error, but there is no way to be certain unless the documentation is specific about it.

I went over the documentation for UIViewController. Is contains:
- 11 functions that specify that your subclass must call super during the implementation.
- 2 functions where the documentation specifies the default implementation is empty.
- 2 functions where you must not call super.
- 8 functions where you properly want to call super.
- 23 functions where I think there is no need to call super.

Based on the above I will admit that the default behaviour should properly be what we have today, but it would be lovely to have compiler warnings for the 11 functions that require it and the 2 functions where we should not call super.

···

On 29 Nov 2016, at 16.05, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 29, 2016, at 1:48 AM, Tino Heth <2th@gmx.de <mailto:2th@gmx.de>> wrote:

Methods that need to be called when they are overridden are
almost always a result of poor design.

Without an explanation or data to back this statement, it's hard to argue about it, and I won't make random shots.

But as a matter of fact, we have to deal with methods which require the behaviour in question now, and I have no idea when Cocoa will be replaced with something better.

That's a great point. I just don't want to punish those who create methods with default implementations that are designed to be completely replaced in subclasses. I suppose that *could* encourage more use of protocols, but that seems like a very unfriendly way to reach a protocol-oriented utopia ;-)

Just out of sheer curiosity:
What would be a better design for a method like viewWillAppear? The obvious alternative that is possible with current Swift and template methods looks really ugly to me:
Not only would you have to add two empty methods to each subclass of UIViewController,

Why two, and why empty? UIViewController would supply its own empty default implementation.

but also rely on that those methods are only overridden once in the hierarchy of inheritance.

There's no law saying you *can't* call super if you absolutely must build a two-level hierarchy below UIViewController (though there are ways around that—the main one being to avoid inheritance hierarchies). I just don't want to create a world where you're always expected to call super everywhere, which is what would happen if we always warn when you don't call super.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name ;-) has been requested several

times, but never got the momentum it deserves.

Considering the current confusion (especially in UIKit), it would be
really nice to have some help from the compiler, and I wonder how
composition and protocols would be helpful here at all.

As an intermediary measure, this seems like an interesting QoI
improvement for the compiler: warn when super.foo() is not called in
the overridden method.

Please no. Methods that need to be called when they are overridden are
almost always a result of poor design.

   “I don't always do Object Oriented Programming, but when I do, I use
   the Template Method Pattern"

understating-the-case-ly yrs,

I agree, that’s why I’m suggesting it be a ObjC-side attribute for use
by e.g. UIKit.

OK, that's fine; it sounded like you were proposing a blanket rule.

Apparently UIKit equally needs an attribute that says “*don't* call
super,” and that would be a good idea for Swift too. It can also be
expressed as “this method is private but overridable,” but I know that
idea gives some people the hives :-).

Regardless of how both of us may feel about UIKit’s design, it is the
largest platform on which apps are made and there’s a chance for the
compiler to enhance the developer experience. I do agree that we
should be careful about condoning the practice for new/Swift-only
frameworks.

Heck, I'm not even going that far. I'm just saying I don't want to
“un-condone” designs that don't require super-calling.

···

on Tue Nov 29 2016, Michael Ilseman <milseman-AT-apple.com> wrote:

On Nov 28, 2016, at 7:22 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Thu Nov 24 2016, Michael Ilseman <swift-evolution@swift.org> wrote:

On Nov 17, 2016, at 2:54 AM, Tino Heth via swift-evolution >>> <swift-evolution@swift.org> wrote:

--
-Dave

While I agree with most of your points Dave, I think forgetting to call super is very much a (hard to debug) real world problem today.

I don’t. I’ve done it a few times but I don’t remember ever having a hard time debugging it.

Especially new developers seems unsure or likely to forget to call super when it is required.

I think my point is this; When you subclass code you have not written yourself you have no idea if the class you are subclassing is "poorly designed" and you should call super somewhere in your documentation. You can make assumptions, read the documentation or use trial and error, but there is no way to be certain unless the documentation is specific about it.

There’s a fine line between being a safe language and being as nannying language and I think proposals about “must call super” and “must not call super” overstep the line - that’s just my opinion, of course.

I went over the documentation for UIViewController. Is contains:
- 11 functions that specify that your subclass must call super during the implementation.
- 2 functions where the documentation specifies the default implementation is empty.
- 2 functions where you must not call super.
- 8 functions where you properly want to call super.
- 23 functions where I think there is no need to call super.

Well that selection should tell us that whether you warn/error for not calling super or warn/error for calling super the decision is going to be the wrong one in some cases.

Also, the two functions where you must not call super are really two functions that you must override. After all, if the subclass fails to override the functions its implementation is going to call super by default, thus breaking the rule.

···

On 29 Nov 2016, at 16:55, Aron Lindberg via swift-evolution <swift-evolution@swift.org> wrote:

Final / closed by default was in and calling super oversteps :)?

Anyways to go back to a more serious point, like Tino said earlier, this is for Dave's comment, sometimes I get the feeling object oriented programming and inheritance are supported but unwelcome a bit. We should not discourage a feature we support, but just make the alternatives so so good that people will not want to use anything but them (unless they really need to use the older practice of course).

I think this is part of being opinionated, but one of the two aspects: do you reward good behaviour over punishing bad one or do you try to make people do something better by rendering the alternative more limited/less appealing?

(In less serious tone) C'mon Crusty, you refused to move to classes with C in the early 80's, staying strong and steady worked, you stuck with structs and function pointers, you have won with Swift... there's no need to spike the ball :P.

···

On 29 Nov 2016, at 17:33, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

On 29 Nov 2016, at 16:55, Aron Lindberg via swift-evolution <swift-evolution@swift.org> wrote:

While I agree with most of your points Dave, I think forgetting to call super is very much a (hard to debug) real world problem today.

I don’t. I’ve done it a few times but I don’t remember ever having a hard time debugging it.

Especially new developers seems unsure or likely to forget to call super when it is required.

I think my point is this; When you subclass code you have not written yourself you have no idea if the class you are subclassing is "poorly designed" and you should call super somewhere in your documentation. You can make assumptions, read the documentation or use trial and error, but there is no way to be certain unless the documentation is specific about it.

There’s a fine line between being a safe language and being as nannying language and I think proposals about “must call super” and “must not call super” overstep the line - that’s just my opinion, of course.

“this method is private but overridable,”

+1 ;-)

It would make the language more orthogonal — but I'm afraid this option died when "open" was added, and I have to admit that it would make things complicated as well:
Methods that shouldn't be called directly (like UIView.draw and layoutSubviews) might require calls to super, and I don't expect that the recently pitched proposal for "typeprivate" will reach the review phase.

If the patterns discussed are generally considered to be a bad fit for Swift and merely legacy, instead of changing the language itself it could be feasible to tinker with the tools instead:
- Smart autocompletion could hide methods that shouldn't be called (and place didDeselectRowAtIndexPath at a less prominent position than the more important didSelectRowAtIndexPath ;-)
- The skeleton for an override could include a call to super if it is needed, which would save a whole bunch of keystrokes
I think there is big potential in the fact that Swift is designed in the same company that builds the most important IDE for it, which could be leveraged with annotations that don't affect the compiler:

While I agree with most of your points Dave, I think forgetting to
call super is very much a (hard to debug) real world problem today.

I don’t. I’ve done it a few times but I don’t remember ever having a hard time debugging it.

Especially new developers seems unsure or likely to forget to call super when it is required.

I think my point is this; When you subclass code you have not
written yourself you have no idea if the class you are subclassing
is "poorly designed" and you should call super somewhere in your
documentation. You can make assumptions, read the documentation or
use trial and error, but there is no way to be certain unless the
documentation is specific about it.

There’s a fine line between being a safe language and being as
nannying language and I think proposals about “must call super” and
“must not call super” overstep the line - that’s just my opinion, of
course.

Final / closed by default was in and calling super oversteps :)?

Anyways to go back to a more serious point, like Tino said earlier,
this is for Dave's comment, sometimes I get the feeling object
oriented programming and inheritance are supported but unwelcome a
bit.

Let me be clear: that is my very personal prejudice, which I admit to
(and then exaggerate a bit for comic effect). Swift has every intention
of being great for, and welcoming, OOP.

We should not discourage a feature we support, but just make the
alternatives so so good that people will not want to use anything but
them (unless they really need to use the older practice of course).

I think this is part of being opinionated, but one of the two aspects:
do you reward good behaviour over punishing bad one or do you try to
make people do something better by rendering the alternative more
limited/less appealing?

(In less serious tone) C'mon Crusty, you refused to move to classes
with C in the early 80's, staying strong and steady worked, you stuck
with structs and function pointers, you have won with Swift... there's
no need to spike the ball :P.

:-). Look, I'm not spiking the ball. I'm saying, the best practice is
to create designs where you don't have to (and even, if supported by the
language, can't) call super. Anyone who doesn't believe me should
search the web for questions about when and whether to call super in
viewWillAppear. APIs that leave programmers with persistent open
questions that don't have clear answers should be improved.

If lots of designs fail to follow that idiom, well, we should certainly
help people to be effective with those designs in spite of their
deficiencies. But we absolutely should *not* punish the best practice
by making the compiler spew warnings when it is followed.

···

on Tue Nov 29 2016, Goffredo Marocchi <panajev-AT-gmail.com> wrote:

On 29 Nov 2016, at 17:33, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

On 29 Nov 2016, at 16:55, Aron Lindberg via swift-evolution <swift-evolution@swift.org> wrote:

--
-Dave