[Discussion] Enforcing Calling Super


(Kyle Sherman) #1

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiredSuper func foo1() { }

    @requiredSuper(start) func foo2() { }

    @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.


Add ability to make a call to super a requirement in subclass overrides
Add ability to make a call to super a requirement in subclass overrides
(Kenny Leung) #2

Hi Kyle.

There is just no way to know what may be required by clients of a framework when it comes time to write actual shipping code. To require users to call super - and to even extend that to knowing whether they should call super at the beginning or end of their methods is too restrictive. If this feature were to go forward, I would limit it to a warning. It may belong more in a linter.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live linter that they call “code inspections”. I like this a lot. It goes waaay beyond compiler-level warnings to offering you suggestions to improve your code, finding sections of duplicated code, anything under the sun. They also allow you to suppress any individual warning by putting an @suppress in your code. Maybe Swift could benefit from another layer like this in general, where you could be warned about a lot of stuff, but not be locked into it.

-Kenny

···

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiredSuper func foo1() { }

    @requiredSuper(start) func foo2() { }

    @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
  • Overridden method must call the superclass’s implementation
  • Overridden method must call the superclass’s implementation as the first line of the method.
  • Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

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


(plx) #3

I think something like this making it into Swift at some point would be great, even if it’s just the `@requiresSuper` form; the positional variants would be even better.

However, I think any proposal like this will be *unusable* unless it *also* includes some way of explicitly marking a specific super-call as “OK, despite how it looks!”…and this is true even if you spec the feature out to only produce warnings, b/c even then you may want to silence those warnings at specific, “known-no-problem” call sites.

Here are two concrete examples:

// suppose `updateConstraints` has `@super(end)` applied to it:
override func updateConstraints() {
  // figure out where a bug is coming from:
  debugLog(“<ISSUE 124>#before constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#before constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  self.updateMyLocalConstraints()
  debugLog(“<ISSUE 124>#after constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#after constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  super.updateConstraints() // <- not last call, but actually ok
  debugLog(“<ISSUE 124>#final constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#final constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
}

// suppose `layoutSubviews` has `@super(begin)` applied to it:
override func layoutSubviews() {
  // capture timing info in debug runs:
  #if DEBUG
  self.performTimedBlock(“updateConstraints”) {
    super.layoutSubviews() // <- not “first call”, but actually ok
    self.layoutMyCustomSubviews()
  }
  #else
  super.layoutSubviews()
  self.layoutMyCustomSubviews()
  #endif
}

…and I picked these because they’re examples where we are actually obeying the “spirit" of the @super annotation.

Such an annotation could either be applied to the method (something like: `@force(@super(end):true)`?), or perhaps an annotation applied to the specific call-site…but right now, I don’t think Swift has anything at all that uses a "call-site” attribute.

Are there any?

···

On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiredSuper func foo1() { }

    @requiredSuper(start) func foo2() { }

    @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

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


(Tino) #4

I'm quite late at this party, but I always thought that it is a pity that NS_REQUIRES_SUPER hasn't been utilized more in Cocoa (all those view-controller methods…), and that it would be a valuable addition to Swift.
In the final-by-default discussion, I even proposed to make this behavior the default, and there haven't been any real arguments why final would be the better choice.

But I think the naming is really poor...
To express the meaning, it should be "superNeedsToBeCalledOnOverride" — that is, of course, a terrible name for an attribute, but "requiresSuper" is just wrong:
You declare something and say "this requires super", but then ignore that requirement, because in the implementation, there is no "super" (at this point, it's actually self instead of super… I'm not that happy with my explanation, but I hope you understand it anyways).

Maybe a native speaker could come up with better words, but so far, I like "compulsive" the most ("mandatory" would be possible as well… and maybe there is a special word for inheritance of duties).

Tino


(Jeremy W. Sherman) #5

Does this handle the case of required super only since a version?

I recall NSView or something like that gaining an awakeFromNib
implementation late, say 10.5 or so, so that one had to conditionalize
calls to [super awakeFromNib] based on whether or not the superclass's
instances responded to that selector. If your code was running on 10.4,
calling super would crash with unrecognized selector; if on 10.5, you were
always supposed to call super.

This suggests some interaction between requiring calls to super and
availability annotations at the least.

···

El Wednesday, February 17, 2016, Kyle Sherman via swift-evolution < swift-evolution@swift.org> escribió:

I just saw that there was a discussion started about this topic just
recently while I was developing this idea with my colleague Peter Livesey.
So, I figured I would submit this proposal for discussion.

The link to the original discussion is here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’
or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](
https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md
)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain
overridden methods to call the superclass’s version of the method. This
change would enforce that the subclass called the superclass's method in
its overridden version at compile time. Also, it would optionally enforce
that the superclass's version would be called before any other
implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](
https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from
simple iOS code. When creating a subclass of UIViewController, you often
need to override methods like viewDidLoad or viewWillAppear. You are
supposed to call super.viewDidLoad or super.viewWillAppear, respectively,
in your overridden implementation. If you don't, you will have undefined
behavior and run into issues. Of course, this type of situation can be
extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the
superclass's code and making a note in the documentation. Quite obviously
this can cause many issues as mistakes can be made by new developers quite
easily who didn't look at the documentation for the method or even seasoned
developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to
@available and @noescape in order to convey this information. Optionally,
the developer can also choose to specify that the super method must be
called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that
any overridden version of the method must call super at the appropriate
time according to the information given in the annotation. The compiler
would also need to ensure that any method that was going to use this
annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because
there is currently no way to enforce super being called in an overridden
method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super
method, the compiler should display an error. The errors that should be
displayed should be similar to:

   1. Overridden method must call the superclass’s implementation
   2. Overridden method must call the superclass’s implementation as the
   first line of the method.
   3. Overridden method must call the superclass’s implementation as the
   last line of the method.

for the cases of `@requiredSuper`, `@requiredSuper(start)`, and
`@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the
access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper
must have access control set to be at least as accessible as the class that
contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional.
Therefore, existing code will be unaffected and no migration of code will
be necessary. However, when APIs are updated to use this new feature, some
code will not compile if the developer did not use the APIs correctly. This
should be a welcomed compilation error as it will result in less buggy code
at runtime. The impact of this change is similar to adding nullability
annotations to Objective-C.

It will be impossible to migrate code automatically, because this
information cannot be derived in any way aside from reading comments if and
only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

--
--
Jeremy W. Sherman
https://jeremywsherman.com/


(Haravikk) #6

Since this proposal is along the same lines as another current thread I’m contributing to I’m of course very much for the basic functionality :wink:
From that other discussion my current preference is towards either an attribute named @super, or allow the super keyword to be used in the method declaration. So a declaration might look like:

  @super(required)
  func someMethod() { … }

Or (if you prefer):

  super(required) func someMethod() { … }

The main ones needed are required and optional, with optional being what we have now, and required simply ensuring that the super method is called (no requirement on where). Options for before and after will be more useful if we get abstract classes whose sole purpose is to be extended, as they may have more specific requirements. The other possibly useful option would @super(replace), in which case super may not be called by extending methods at all, as it’s implementation may be very tightly coupled to the specific implementation at that level, thus requiring a sub-class to re-implement it; the parent method could also be some kind of stub for a feature it doesn’t support, but which was required by a protocol for example.

Howard Lovatt also mentioned another interesting extension to the idea which is that methods would effectively become final by default, requiring a @super attribute if they are to be overridable, which I think would be good for ensuring that only classes designed with extension in mind can actually be extended. For this reason the @super attribute could also be used on a class to set a new default for all methods. If we go with this aspect then the final keyword would probably be moved into the @super attribute for methods (properties would still have access to it though I think).

There is just no way to know what may be required by clients of a framework when it comes time to write actual shipping code. To require users to call super - and to even extend that to knowing whether they should call super at the beginning or end of their methods is too restrictive. If this feature were to go forward, I would limit it to a warning. It may belong more in a linter.

A lot of people have reacted negatively to the idea of before and after requirements, but I think it’s important to note that they’re unlikely to be commonly added; in most cases it won’t matter when the super method is called so required or optional should be used as appropriate. Before and after requirements are more useful for abstract or abstract-style classes that offer partial implementations specifically designed to be extended, in which case the order may be more important. Most of the time the deciding factor will be whether your method performs some kind of updates to cached values, in which case it will be important that it is called; the requirement can also be used to serve as a reminder to read the documentation about how exactly the parent method should be used by extending classes, if it has any more unusual caveats.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live linter that they call “code inspections”. I like this a lot. It goes waaay beyond compiler-level warnings to offering you suggestions to improve your code, finding sections of duplicated code, anything under the sun. They also allow you to suppress any individual warning by putting an @suppress in your code. Maybe Swift could benefit from another layer like this in general, where you could be warned about a lot of stuff, but not be locked into it.

It could make sense to have an option for whether breaking a requirement produces a warning or an error? For example @super(required, warn) will warn the developer that they are going against the parent class’ requirement to include the super method, but won’t actually stop them from doing so if they really want to. This could provide a useful middle-ground between optional and required, plus if the code of the parent class isn’t under your control it gives you a fallback until there’s an update if the warning behaviour were the default, with @super(required, error) style declarations for developers who really know what their parent class needs from sub-classes.

It’s also worth considering that most code will be under your control, so you’ll just need to tweak (or add) the requirements, in the latter case it forces you to consider how that class may be extended which I think is a good thing.

···

On 17 Feb 2016, at 19:55, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
  • Overridden method must call the superclass’s implementation
  • Overridden method must call the superclass’s implementation as the first line of the method.
  • Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

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


(Peter Livesey) #7

+1 to most of what Andrew Bennet said.

I also disagree that implicit calls is the right solution. If the compiler
autocompletes the super call for me, there's little reason for this. It
just makes debugging much harder.

For the generalization part, honestly, it just looks too complicated. I
don't think this feature should require a chapter in the learn swift book
to learn all the options - it should be a footnote. In Kyle's original
proposal, one of the motivations for this feature is making the language
easier to learn - calling super isn't natural for some beginners and having
the compiler warn you when you're missing it is really helpful.

@plx: I think you bring up a great point with start and end. It may hint at
a deeper problem as to how to define start and end. More code runs than the
lines you write. There are retains and releases inserted by ARC, there are
assembly instructions run, etc. I think your block examples give a great
example of when this may be not desirable.

I think we have a good example of when not calling super can lead to bad
bugs (viewDidAppear), but do we have an example of when calling super in
the wrong place can lead to a bug? In most cases, does it matter?

···

On Thu, Feb 18, 2016 at 7:02 AM plx via swift-evolution < swift-evolution@swift.org> wrote:

I think something like this making it into Swift at some point would be
great, even if it’s just the `@requiresSuper` form; the positional variants
would be even better.

However, I think any proposal like this will be *unusable* unless it
*also* includes some way of explicitly marking a specific super-call as
“OK, despite how it looks!”…and this is true even if you spec the feature
out to only produce warnings, b/c even then you may want to silence those
warnings at specific, “known-no-problem” call sites.

Here are two concrete examples:

// suppose `updateConstraints` has `@super(end)` applied to it:
override func updateConstraints() {
  // figure out where a bug is coming from:
  debugLog(“<ISSUE 124>#before constraints.horizontal:
\(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#before constraints.vertical:
\(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  self.updateMyLocalConstraints()
  debugLog(“<ISSUE 124>#after constraints.horizontal:
\(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#after constraints.vertical:
\(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  super.updateConstraints() // <- not last call, but actually ok
  debugLog(“<ISSUE 124>#final constraints.horizontal:
\(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#final constraints.vertical:
\(self.constraintsAffectingLayoutForAxis(.Vertical))”)
}

// suppose `layoutSubviews` has `@super(begin)` applied to it:
override func layoutSubviews() {
  // capture timing info in debug runs:
  #if DEBUG
  self.performTimedBlock(“updateConstraints”) {
    super.layoutSubviews() // <- not “first call”, but actually ok
    self.layoutMyCustomSubviews()
  }
  #else
  super.layoutSubviews()
  self.layoutMyCustomSubviews()
  #endif
}

…and I picked these because they’re examples where we are actually obeying
the “spirit" of the @super annotation.

Such an annotation could either be applied to the method (something like:
`@force(@super(end):true)`?), or perhaps an annotation applied to the
specific call-site…but right now, I don’t think Swift has anything at all
that uses a "call-site” attribute.

Are there any?

On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution < > swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just
recently while I was developing this idea with my colleague Peter Livesey.
So, I figured I would submit this proposal for discussion.

The link to the original discussion is here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’
or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](
https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md
)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain
overridden methods to call the superclass’s version of the method. This
change would enforce that the subclass called the superclass's method in
its overridden version at compile time. Also, it would optionally enforce
that the superclass's version would be called before any other
implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](
https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from
simple iOS code. When creating a subclass of UIViewController, you often
need to override methods like viewDidLoad or viewWillAppear. You are
supposed to call super.viewDidLoad or super.viewWillAppear, respectively,
in your overridden implementation. If you don't, you will have undefined
behavior and run into issues. Of course, this type of situation can be
extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the
superclass's code and making a note in the documentation. Quite obviously
this can cause many issues as mistakes can be made by new developers quite
easily who didn't look at the documentation for the method or even seasoned
developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to
@available and @noescape in order to convey this information. Optionally,
the developer can also choose to specify that the super method must be
called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that
any overridden version of the method must call super at the appropriate
time according to the information given in the annotation. The compiler
would also need to ensure that any method that was going to use this
annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because
there is currently no way to enforce super being called in an overridden
method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super
method, the compiler should display an error. The errors that should be
displayed should be similar to:

   1. Overridden method must call the superclass’s implementation
   2. Overridden method must call the superclass’s implementation as the
   first line of the method.
   3. Overridden method must call the superclass’s implementation as the
   last line of the method.

for the cases of `@requiredSuper`, `@requiredSuper(start)`, and
`@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the
access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper
must have access control set to be at least as accessible as the class that
contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional.
Therefore, existing code will be unaffected and no migration of code will
be necessary. However, when APIs are updated to use this new feature, some
code will not compile if the developer did not use the APIs correctly. This
should be a welcomed compilation error as it will result in less buggy code
at runtime. The impact of this change is similar to adding nullability
annotations to Objective-C.

It will be impossible to migrate code automatically, because this
information cannot be derived in any way aside from reading comments if and
only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Goffredo Marocchi) #8

I hope we will be able to use something like the clang diagnostic macro's to do that...

···

Sent from my iPhone

On 18 Feb 2016, at 15:02, plx via swift-evolution <swift-evolution@swift.org> wrote:

I think something like this making it into Swift at some point would be great, even if it’s just the `@requiresSuper` form; the positional variants would be even better.

However, I think any proposal like this will be *unusable* unless it *also* includes some way of explicitly marking a specific super-call as “OK, despite how it looks!”…and this is true even if you spec the feature out to only produce warnings, b/c even then you may want to silence those warnings at specific, “known-no-problem” call sites.

Here are two concrete examples:

// suppose `updateConstraints` has `@super(end)` applied to it:
override func updateConstraints() {
  // figure out where a bug is coming from:
  debugLog(“<ISSUE 124>#before constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#before constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  self.updateMyLocalConstraints()
  debugLog(“<ISSUE 124>#after constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#after constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
  super.updateConstraints() // <- not last call, but actually ok
  debugLog(“<ISSUE 124>#final constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
  debugLog(“<ISSUE 124>#final constraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
}

// suppose `layoutSubviews` has `@super(begin)` applied to it:
override func layoutSubviews() {
  // capture timing info in debug runs:
  #if DEBUG
  self.performTimedBlock(“updateConstraints”) {
    super.layoutSubviews() // <- not “first call”, but actually ok
    self.layoutMyCustomSubviews()
  }
  #else
  super.layoutSubviews()
  self.layoutMyCustomSubviews()
  #endif
}

…and I picked these because they’re examples where we are actually obeying the “spirit" of the @super annotation.

Such an annotation could either be applied to the method (something like: `@force(@super(end):true)`?), or perhaps an annotation applied to the specific call-site…but right now, I don’t think Swift has anything at all that uses a "call-site” attribute.

Are there any?

On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiredSuper func foo1() { }

    @requiredSuper(start) func foo2() { }

    @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Kyle Sherman) #9

Thanks for the replies.

Kenny: After thinking about it more, discussing with Peter, and looking Haravikk’s comments, I think the best thing would be for this to be a warning as suggested. I respectfully disagree that as a library creator you would not be able to know that a call to super should be required. A perfect example of this is the one stated in the proposal: viewDidLoad, viewWillAppear, etc. In these cases, the library writers know that the super version must be called and no matter what the subclasser does, they will not be able to have correct behavior without calling super. This is present in many places throughout the iOS SDK as example. In the static analyzer in Xcode, for ObjC code, it warns when the developer doesn’t call super in certain cases. Having these annotations would allow for developers to specify this for their own code. Being able to suppress the warning could also be a good feature, but I definitely don’t feel it would be necessary for the implementation of the feature.

Haravikk: I don’t agree with using “(required)” as that will be a sort of overloaded usage of the keyword. Also, I think that simply not specifying anything would be a better way to go about it. So, @super would mean you require the super method to be called, and simply not having an annotation means that you do not have to call the super method. Peter and I have a separate proposal that we will put up here soon for extending the “required” keyword for all methods that I think will solve the problem of abstract classes. I don’t think that we should conflate that issue, which we feel is a separate issue, in with the issue of requiring the super method to be called. Along the same lines, final by default was already being discussed much earlier and I believe there was already a conclusion to that saying it would not be implemented. I think the final keyword should stay separate, especially since it is a compiler error vs this which we are now saying would be a warning.

-Kyle

···

On Feb 17, 2016, at 12:31 PM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

Since this proposal is along the same lines as another current thread I’m contributing to I’m of course very much for the basic functionality :wink:
From that other discussion my current preference is towards either an attribute named @super, or allow the super keyword to be used in the method declaration. So a declaration might look like:

  @super(required)
  func someMethod() { … }

Or (if you prefer):

  super(required) func someMethod() { … }

The main ones needed are required and optional, with optional being what we have now, and required simply ensuring that the super method is called (no requirement on where). Options for before and after will be more useful if we get abstract classes whose sole purpose is to be extended, as they may have more specific requirements. The other possibly useful option would @super(replace), in which case super may not be called by extending methods at all, as it’s implementation may be very tightly coupled to the specific implementation at that level, thus requiring a sub-class to re-implement it; the parent method could also be some kind of stub for a feature it doesn’t support, but which was required by a protocol for example.

Howard Lovatt also mentioned another interesting extension to the idea which is that methods would effectively become final by default, requiring a @super attribute if they are to be overridable, which I think would be good for ensuring that only classes designed with extension in mind can actually be extended. For this reason the @super attribute could also be used on a class to set a new default for all methods. If we go with this aspect then the final keyword would probably be moved into the @super attribute for methods (properties would still have access to it though I think).

On 17 Feb 2016, at 19:55, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

There is just no way to know what may be required by clients of a framework when it comes time to write actual shipping code. To require users to call super - and to even extend that to knowing whether they should call super at the beginning or end of their methods is too restrictive. If this feature were to go forward, I would limit it to a warning. It may belong more in a linter.

A lot of people have reacted negatively to the idea of before and after requirements, but I think it’s important to note that they’re unlikely to be commonly added; in most cases it won’t matter when the super method is called so required or optional should be used as appropriate. Before and after requirements are more useful for abstract or abstract-style classes that offer partial implementations specifically designed to be extended, in which case the order may be more important. Most of the time the deciding factor will be whether your method performs some kind of updates to cached values, in which case it will be important that it is called; the requirement can also be used to serve as a reminder to read the documentation about how exactly the parent method should be used by extending classes, if it has any more unusual caveats.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live linter that they call “code inspections”. I like this a lot. It goes waaay beyond compiler-level warnings to offering you suggestions to improve your code, finding sections of duplicated code, anything under the sun. They also allow you to suppress any individual warning by putting an @suppress in your code. Maybe Swift could benefit from another layer like this in general, where you could be warned about a lot of stuff, but not be locked into it.

It could make sense to have an option for whether breaking a requirement produces a warning or an error? For example @super(required, warn) will warn the developer that they are going against the parent class’ requirement to include the super method, but won’t actually stop them from doing so if they really want to. This could provide a useful middle-ground between optional and required, plus if the code of the parent class isn’t under your control it gives you a fallback until there’s an update if the warning behaviour were the default, with @super(required, error) style declarations for developers who really know what their parent class needs from sub-classes.

It’s also worth considering that most code will be under your control, so you’ll just need to tweak (or add) the requirements, in the latter case it forces you to consider how that class may be extended which I think is a good thing.

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
  • Overridden method must call the superclass’s implementation
  • Overridden method must call the superclass’s implementation as the first line of the method.
  • Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Peter Livesey) #10

I am not sure why some compiler hints use @ and others don't, but this
feature seems closer in functionality to @available instead of final or
required.

So I agree that overloading the required keyword seems out of place and
using a different syntax (using @) seems more appropriate.

···

On Wed, Feb 17, 2016 at 2:26 PM Kyle Sherman via swift-evolution < swift-evolution@swift.org> wrote:

Thanks for the replies.

Kenny: After thinking about it more, discussing with Peter, and looking
Haravikk’s comments, I think the best thing would be for this to be a
warning as suggested. I respectfully disagree that as a library creator you
would not be able to know that a call to super should be required. A
perfect example of this is the one stated in the proposal: viewDidLoad,
viewWillAppear, etc. In these cases, the library writers know that the
super version must be called and no matter what the subclasser does, they
will not be able to have correct behavior without calling super. This is
present in many places throughout the iOS SDK as example. In the static
analyzer in Xcode, for ObjC code, it warns when the developer doesn’t call
super in certain cases. Having these annotations would allow for developers
to specify this for their own code. Being able to suppress the warning
could also be a good feature, but I definitely don’t feel it would be
necessary for the implementation of the feature.

Haravikk: I don’t agree with using “(required)” as that will be a sort of
overloaded usage of the keyword. Also, I think that simply not specifying
anything would be a better way to go about it. So, @super would mean you
require the super method to be called, and simply not having an annotation
means that you do not have to call the super method. Peter and I have a
separate proposal that we will put up here soon for extending the
“required” keyword for all methods that I think will solve the problem of
abstract classes. I don’t think that we should conflate that issue, which
we feel is a separate issue, in with the issue of requiring the super
method to be called. Along the same lines, final by default was already
being discussed much earlier and I believe there was already a conclusion
to that saying it would not be implemented. I think the final keyword
should stay separate, especially since it is a compiler error vs this which
we are now saying would be a warning.

-Kyle

On Feb 17, 2016, at 12:31 PM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

Since this proposal is along the same lines as another current thread I’m
contributing to I’m of course very much for the basic functionality :wink:
From that other discussion my current preference is towards either an
attribute named @super, or allow the super keyword to be used in the method
declaration. So a declaration might look like:

@super(required)
func someMethod() { … }

Or (if you prefer):

super(required) func someMethod() { … }

The main ones needed are required and optional, with optional being what
we have now, and required simply ensuring that the super method is called
(no requirement on where). Options for before and after will be more useful
if we get abstract classes whose sole purpose is to be extended, as they
may have more specific requirements. The other possibly useful option would
@super(replace), in which case super may not be called by extending methods
at all, as it’s implementation may be very tightly coupled to the specific
implementation at that level, thus requiring a sub-class to re-implement
it; the parent method could also be some kind of stub for a feature it
doesn’t support, but which was required by a protocol for example.

Howard Lovatt also mentioned another interesting extension to the idea
which is that methods would effectively become final by default, requiring
a @super attribute if they are to be overridable, which I think would be
good for ensuring that only classes designed with extension in mind can
actually be extended. For this reason the @super attribute could also be
used on a class to set a new default for all methods. If we go with this
aspect then the final keyword would probably be moved into the @super
attribute for methods (properties would still have access to it though I
think).

On 17 Feb 2016, at 19:55, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:

There is just no way to know what may be required by clients of a
framework when it comes time to write actual shipping code. To require
users to call super - and to even extend that to knowing whether they
should call super at the beginning or end of their methods is too
restrictive. If this feature were to go forward, I would limit it to a
warning. It may belong more in a linter.

A lot of people have reacted negatively to the idea of before and after
requirements, but I think it’s important to note that they’re unlikely to
be commonly added; in most cases it won’t matter when the super method is
called so required or optional should be used as appropriate. Before and
after requirements are more useful for abstract or abstract-style classes
that offer partial implementations specifically designed to be extended, in
which case the order may be more important. Most of the time the deciding
factor will be whether your method performs some kind of updates to cached
values, in which case it will be important that it is called; the
requirement can also be used to serve as a reminder to read the
documentation about how exactly the parent method should be used by
extending classes, if it has any more unusual caveats.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live
linter that they call “code inspections”. I like this a lot. It goes waaay
beyond compiler-level warnings to offering you suggestions to improve your
code, finding sections of duplicated code, anything under the sun. They
also allow you to suppress any individual warning by putting an @suppress
in your code. Maybe Swift could benefit from another layer like this in
general, where you could be warned about a lot of stuff, but not be locked
into it.

It could make sense to have an option for whether breaking a requirement
produces a warning or an error? For example @super(required, warn) will
warn the developer that they are going against the parent class’
requirement to include the super method, but won’t actually stop them from
doing so if they really want to. This could provide a useful middle-ground
between optional and required, plus if the code of the parent class isn’t
under your control it gives you a fallback until there’s an update if the
warning behaviour were the default, with @super(required, error) style
declarations for developers who really know what their parent class needs
from sub-classes.

It’s also worth considering that most code will be under your control, so
you’ll just need to tweak (or add) the requirements, in the latter case it
forces you to consider how that class may be extended which I think is a
good thing.

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution < > swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just
recently while I was developing this idea with my colleague Peter Livesey.
So, I figured I would submit this proposal for discussion.

The link to the original discussion is here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’
or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](
https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md
)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain
overridden methods to call the superclass’s version of the method. This
change would enforce that the subclass called the superclass's method in
its overridden version at compile time. Also, it would optionally enforce
that the superclass's version would be called before any other
implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](
https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from
simple iOS code. When creating a subclass of UIViewController, you often
need to override methods like viewDidLoad or viewWillAppear. You are
supposed to call super.viewDidLoad or super.viewWillAppear, respectively,
in your overridden implementation. If you don't, you will have undefined
behavior and run into issues. Of course, this type of situation can be
extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the
superclass's code and making a note in the documentation. Quite obviously
this can cause many issues as mistakes can be made by new developers quite
easily who didn't look at the documentation for the method or even seasoned
developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to
@available and @noescape in order to convey this information. Optionally,
the developer can also choose to specify that the super method must be
called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that
any overridden version of the method must call super at the appropriate
time according to the information given in the annotation. The compiler
would also need to ensure that any method that was going to use this
annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because
there is currently no way to enforce super being called in an overridden
method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super
method, the compiler should display an error. The errors that should be
displayed should be similar to:
• Overridden method must call the superclass’s implementation
• Overridden method must call the superclass’s implementation as the first
line of the method.
• Overridden method must call the superclass’s implementation as the last
line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and
`@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the
access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper
must have access control set to be at least as accessible as the class that
contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional.
Therefore, existing code will be unaffected and no migration of code will
be necessary. However, when APIs are updated to use this new feature, some
code will not compile if the developer did not use the APIs correctly. This
should be a welcomed compilation error as it will result in less buggy code
at runtime. The impact of this change is similar to adding nullability
annotations to Objective-C.

It will be impossible to migrate code automatically, because this
information cannot be derived in any way aside from reading comments if and
only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Haravikk) #11

I don’t believe so, at least in the case of a @super attribute, in which case it’s an option of that attribute, so a separate use-case, of course if there’s another term that can be used then I’ve no particular attachment to required, it’s just the most obvious term to me.

While I agree that @super on its own should imply required, I think we should still have the ability to explicitly state that that is the case (personally I prefer to be as clear as possible rather than relying on defaults) in cases like these.

···

On 17 Feb 2016, at 22:26, Kyle Sherman <kyledsherman@gmail.com> wrote:

Haravikk: I don’t agree with using “(required)” as that will be a sort of overloaded usage of the keyword.


(Dennis Weissmann) #12

Can’t the compiler generate them?

@requiredSuper(end) func foo3()

If the compiler can tell you that you need to call super() at the very beginning (or the very end) of a method, it should be able to do that for you.

What I imagine is a syntax like this:

Note: I’ve changed the syntax to # because I think this is compiler-magic and as Chris mentioned the following in the property behavior thread:

Where [lazy] is currently used, could the syntax instead be #behavior(lazy)? That prevents a possible future naming clash, keeps the # meaning compiler-magic, and doesn't use the [], which is contentious.

class Base {

  #requireSuperStart // nitpicking, but I’d like #requireSuperAtBeginning actually better
  func mustCallSuperMethod() {
    // Some code
  }

}

class Subclass: Base {

  // All subclasses automatically (implicitly) inherit #requireSuperX, this is visible across module boundaries
  override func mustCallSuperMethod() {
    // Do your setup
  }
  
}

The compiler would inject (invisible to the dev) the super() call at the very beginning. The same is true for #requireSuperEnd.
I don’t think we need a #requireSuper because it means we don’t care when it’s called so the compiler can decide where to put it.

The only problematic point might be a super call with arguments but I have never ever changed the argument of a super call (e.g. in viewDidAppear(animated: Bool) I never called the super implementation other than super.viewDidAppear(animated)).

- Dennis, who is sick => please forgive any mistakes or oversights :pray:

···

On Feb 17, 2016, at 11:26 PM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

Thanks for the replies.

Kenny: After thinking about it more, discussing with Peter, and looking Haravikk’s comments, I think the best thing would be for this to be a warning as suggested. I respectfully disagree that as a library creator you would not be able to know that a call to super should be required. A perfect example of this is the one stated in the proposal: viewDidLoad, viewWillAppear, etc. In these cases, the library writers know that the super version must be called and no matter what the subclasser does, they will not be able to have correct behavior without calling super. This is present in many places throughout the iOS SDK as example. In the static analyzer in Xcode, for ObjC code, it warns when the developer doesn’t call super in certain cases. Having these annotations would allow for developers to specify this for their own code. Being able to suppress the warning could also be a good feature, but I definitely don’t feel it would be necessary for the implementation of the feature.

Haravikk: I don’t agree with using “(required)” as that will be a sort of overloaded usage of the keyword. Also, I think that simply not specifying anything would be a better way to go about it. So, @super would mean you require the super method to be called, and simply not having an annotation means that you do not have to call the super method. Peter and I have a separate proposal that we will put up here soon for extending the “required” keyword for all methods that I think will solve the problem of abstract classes. I don’t think that we should conflate that issue, which we feel is a separate issue, in with the issue of requiring the super method to be called. Along the same lines, final by default was already being discussed much earlier and I believe there was already a conclusion to that saying it would not be implemented. I think the final keyword should stay separate, especially since it is a compiler error vs this which we are now saying would be a warning.

-Kyle

On Feb 17, 2016, at 12:31 PM, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Since this proposal is along the same lines as another current thread I’m contributing to I’m of course very much for the basic functionality :wink:
From that other discussion my current preference is towards either an attribute named @super, or allow the super keyword to be used in the method declaration. So a declaration might look like:

  @super(required)
  func someMethod() { … }

Or (if you prefer):

  super(required) func someMethod() { … }

The main ones needed are required and optional, with optional being what we have now, and required simply ensuring that the super method is called (no requirement on where). Options for before and after will be more useful if we get abstract classes whose sole purpose is to be extended, as they may have more specific requirements. The other possibly useful option would @super(replace), in which case super may not be called by extending methods at all, as it’s implementation may be very tightly coupled to the specific implementation at that level, thus requiring a sub-class to re-implement it; the parent method could also be some kind of stub for a feature it doesn’t support, but which was required by a protocol for example.

Howard Lovatt also mentioned another interesting extension to the idea which is that methods would effectively become final by default, requiring a @super attribute if they are to be overridable, which I think would be good for ensuring that only classes designed with extension in mind can actually be extended. For this reason the @super attribute could also be used on a class to set a new default for all methods. If we go with this aspect then the final keyword would probably be moved into the @super attribute for methods (properties would still have access to it though I think).

On 17 Feb 2016, at 19:55, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

There is just no way to know what may be required by clients of a framework when it comes time to write actual shipping code. To require users to call super - and to even extend that to knowing whether they should call super at the beginning or end of their methods is too restrictive. If this feature were to go forward, I would limit it to a warning. It may belong more in a linter.

A lot of people have reacted negatively to the idea of before and after requirements, but I think it’s important to note that they’re unlikely to be commonly added; in most cases it won’t matter when the super method is called so required or optional should be used as appropriate. Before and after requirements are more useful for abstract or abstract-style classes that offer partial implementations specifically designed to be extended, in which case the order may be more important. Most of the time the deciding factor will be whether your method performs some kind of updates to cached values, in which case it will be important that it is called; the requirement can also be used to serve as a reminder to read the documentation about how exactly the parent method should be used by extending classes, if it has any more unusual caveats.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live linter that they call “code inspections”. I like this a lot. It goes waaay beyond compiler-level warnings to offering you suggestions to improve your code, finding sections of duplicated code, anything under the sun. They also allow you to suppress any individual warning by putting an @suppress in your code. Maybe Swift could benefit from another layer like this in general, where you could be warned about a lot of stuff, but not be locked into it.

It could make sense to have an option for whether breaking a requirement produces a warning or an error? For example @super(required, warn) will warn the developer that they are going against the parent class’ requirement to include the super method, but won’t actually stop them from doing so if they really want to. This could provide a useful middle-ground between optional and required, plus if the code of the parent class isn’t under your control it gives you a fallback until there’s an update if the warning behaviour were the default, with @super(required, error) style declarations for developers who really know what their parent class needs from sub-classes.

It’s also worth considering that most code will be under your control, so you’ll just need to tweak (or add) the requirements, in the latter case it forces you to consider how that class may be extended which I think is a good thing.

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.

The link to the original discussion is here: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
  • Overridden method must call the superclass’s implementation
  • Overridden method must call the superclass’s implementation as the first line of the method.
  • Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Kyle Sherman) #13

Thank you everyone for the feedback. I think that suppressing the warnings generated by this is something that Swift doesn’t support at all right now. Therefore, I think that if/when the ability to suppress warnings is added, it will work for this as well. I don’t think this proposal needs to say anything about being able to suppress the warning, because it would be done at the call site anyway.

@plx: Given the examples you provided and my thoughts above, I think in this case you would just see the warning and just need to ignore it, because you know that you are doing it correctly. I think that is probably best at this point. The real solution would be to really enforce that member variables are not mutated according to the start/end parameter, but I don’t think that is really necessary as the warning can be ignored in these cases.

@haravikk: I still don’t see a reason to have a parameter for saying that it is required, since as we both agreed, it makes sense that only when the attribute is defined, is it required. Having the attribute declared but not have required would basically be invalid. I think baking it into the name like I originally suggested is probably best, as @super by itself is probably not explicit enough. The naming of these attributes and casing are being debated in a different thread, so I think I will just submit my suggestion with the idea that it can be corrected to fit what they decide in the other thread.

Here is an updated version of the proposal. If no one has any other comments. Please review and let me know, because I would like to submit it for a review after I get comments on this version.

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Kyle Sherman](https://github.com/drumnkyle)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called either before any other implementation in the method (similar to initialization rules) or as the last line in the method.

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010509.html)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an attribute similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the attribute to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the attribute. The compiler would also need to ensure that any method that was going to use this attribute had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiresSuper func foo1() { }

    @requiresSuper(start) func foo2() { }

    @requiresSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display a warning. The warnings that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiresSuper`, `@requiresSuper(start)`, and `@requiresSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiresSuper func foo() { }
}

The compiler should show a warning, such as “A method using @requiresSuper must have access control set to be at least as accessible as the class that contains it”.

There can also be a simple fix-it that adds in the call to the super’s method. The specifics of the exact name and syntax is flexible as long as it has the 3 features proposed and produces a warning.

## Impact on existing code

The good thing about this change is that it will not have any impact on existing Swift code. This is an optional attribute provided by the developer. Therefore, if the attribute is not used, nothing is changed.

Unfortunately, there is no good way to automatically migrate code to use this new attribute, because the information would have only been embedded in comments previously. Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability attributes to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

···

I hope we will be able to use something like the clang diagnostic macro's to do that...

Sent from my iPhone

On 18 Feb 2016, at 15:02, plx via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:

> I think something like this making it into Swift at some point would be great, even if it’s just the `@requiresSuper` form; the positional variants would be even better.
>
> However, I think any proposal like this will be *unusable* unless it *also* includes some way of explicitly marking a specific super-call as “OK, despite how it looks!”…and this is true even if you spec the feature out to only produce warnings, b/c even then you may want to silence those warnings at specific, “known-no-problem” call sites.
>
> Here are two concrete examples:
>
> // suppose `updateConstraints` has `@super(end)` applied to it:
> override func updateConstraints() {
> // figure out where a bug is coming from:
> debugLog(“<ISSUE 124>#before constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> debugLog(“<ISSUE 124>#beforeconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> self.updateMyLocalConstraints()
> debugLog(“<ISSUE 124>#after constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> debugLog(“<ISSUE 124>#afterconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> super.updateConstraints() //<- not last call, but actually ok
> debugLog(“<ISSUE 124>#final constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> debugLog(“<ISSUE 124>#finalconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> }
>
> // suppose `layoutSubviews` has `@super(begin)` applied to it:
> override func layoutSubviews() {
> // capture timing info in debug runs:
> #if DEBUG
> self.performTimedBlock(“updateConstraints”) {
> super.layoutSubviews() //<- not “first call”, but actually ok
> self.layoutMyCustomSubviews()
> }
> #else
> super.layoutSubviews()
> self.layoutMyCustomSubviews()
> #endif
> }
>
> …and I picked these because they’re examples where we are actually obeying the “spirit" of the @super annotation.
>
> Such an annotation could either be applied to the method (something like: `@force(@super(end):true)`?), or perhaps an annotation applied to the specific call-site…but right now, I don’t think Swift has anything at all that uses a "call-site” attribute.
>
> Are there any?
>
> > On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.
> >
> > The link to the original discussion is here:https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html
> >
> > The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall
> >
> > -Kyle
> >
> > # Enforcing Calling Super
> >
> > * Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
> > * Author(s): [Swift Developer](https://github.com/swiftdev)
> > * Status: **Awaiting review**
> > * Review manager: TBD
> >
> > ## Introduction
> >
> > Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).
> >
> > Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)
> >
> > ## Motivation
> >
> > A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.
> > Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.
> > ## Proposed solution
> >
> > The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.
> > The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.
> > This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.
> >
> > ## Detailed design
> >
> > A possible implementation of this may look like this:
> > ```
> > class MyClass {
> > @requiredSuper func foo1() { }
> >
> > @requiredSuper(start) func foo2() { }
> > @requiredSuper(end) func foo3() { }
> > }
> > ```
> >
> > Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
> > Overridden method must call the superclass’s implementation
> >
> > Overridden method must call the superclass’s implementation as the first line of the method.
> >
> > Overridden method must call the superclass’s implementation as the last line of the method.
> >
> >
> > for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.
> >
> > The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:
> > ```
> > public class MyClass {
> > @requiredSuper func foo() { }
> > }
> > ```
> >
> > The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.
> >
> > ## Impact on existing code
> >
> > Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.
> > It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.
> >
> > ## Alternatives considered
> > The alternative would simply be to not implement this feature.
> >
> > _______________________________________________
> > 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


(Jeremy Pereira) #14

Thanks for the replies.

Kenny: After thinking about it more, discussing with Peter, and looking Haravikk’s comments, I think the best thing would be for this to be a warning as suggested. I respectfully disagree that as a library creator you would not be able to know that a call to super should be required.

I disagree. You can’t possibly know all the use-cases in which your class might be subclassed.

In particular, it is absurd to enforce having the call to super as the first or last line of the method. That would stop me doing things like this:

    override func viewDidLoad()
    {
        print(“About to run super.viewDidLoad()”)
        super.viewDidLoad()
        print(“Finished super.viewDidLoad()”)
    }

Then there’s the perfectly reasonable case like this:

    override func viewDidLoad()
    {
        functionThatCallsSuperViewDidLoad()
    }

Why shouldn’t I be allowed to do that?

I’m not a fan of "final by default” either because people will leave the virtual (or whatever is called) keyword off through laziness, not because it is definitely impossible to override the method or or subclass the class and make their classes impossible to reuse.

I would, however, accept a warning as long as I can turn it off. I like my tools sharp even though there is a higher risk I might cut myself.

···

On 17 Feb 2016, at 22:26, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

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


(Andrew Bennett) #15

I like what this thread could mean for better protocol conformance, but I
think that requiring things like start/end need to be used sparingly, and
only when a clean API can't be designed without it. This is mainly because
of the reasons Kenny mentions, but also due to the restrictions it may
place on debugging.

*Require once*
Worth considering is that you may want to enforce that super is only called
once, I'm sure there's counter examples, but it seems like something worth
considering.

*Implicit calls (-1)*
I like what Dennis has suggested with implicit calls. Although I don't
think it would work in the general case, and I think it's sufficiently
unexpected that you wouldn't want it to only happen sometimes.

I've had a few hard to track bugs that have happened in the super call at
the start of a method. For things like delegate methods for out-of-module
classes it's useful to be able to put a breakpoint before the super call to
debug it.

It's also possible that super must be called first, but you want to use the
result of that call.

*#requireSuper (+1)*
I think we would definitely need #requireSuper, for example: if other
operations must be performed either side of the call.

I believe there's a few Cocoa cases where calling multiple methods in a
specific order is required, but not necessarily as the first or last calls.
For example:

UIViewController's willMoveToParentViewController the documentation states:

If you are implementing your own container view controller, it must call
the willMoveToParentViewController: method of the child view controller
before calling the removeFromParentViewController method, passing in a
parent value of nil.

This means that willMoveToParentViewController: cannot be last, nor is it
explicitly required to be first. This allows calls before the call to
super, and requires a call after it. I imagine a lot of code would break if
this was made more strict. Perhaps this example could be fixed with a
different UIViewController API, but that's out of scope.

*Generalisation?*
I wonder if this proposal could/should be generalised to something like
this (all arguments optional):

@callRequirements(

    super=first|last|once|never|optional,

    require=[someProtocolMethod,someClassMethod],

    require_once=[closureArgument],

    require_ordered=[super,someProtocolMethod(:argument:)],
    disallow=[someProtocolProperty])

The identifiers would have to be defined and unambiguous on the current
type or function.

By closureArgument I mean that a closure passed to the function must be
called.

Perhaps require_ordered can be removed if existing APIs can be made to use
an cleaner/enforceable pattern.

Note that requiring a closureArgument to be called potentially overlaps
with another thread "Guaranteed closure execution" (with an argument like
@noescape):

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008167.html

My suggestion lacks some flexibility, at some point it would be nice to be
able to write custom validator functions (for protocols and classes) that
can be referenced by name. There's a similar proposal for that recently
called "Proposal: Allow functions to participate in the compile so they can
generate warnings about their usage" if you're interested:

http://comments.gmane.org/gmane.comp.lang.swift.evolution/6870

This could allow us to do things like this:

@verifyCall(superFirst, pure, disallowDirectPropertyUsage)

Andrew Bennett

···

On Thursday, 18 February 2016, Dennis Weissmann via swift-evolution < swift-evolution@swift.org> wrote:

Can’t the compiler generate them?

@requiredSuper(end) func foo3()

If the compiler can tell you that you need to call super() at the very
beginning (or the very end) of a method, it should be able to do that for
you.

What I imagine is a syntax like this:

Note: I’ve changed the syntax to # because I think this is compiler-magic
and as Chris mentioned the following in the property behavior thread:

Where [lazy] is currently used, could the syntax instead be
#behavior(lazy)? That prevents a possible future naming clash, keeps the #
meaning compiler-magic, and doesn't use the [], which is contentious.

class Base {

  #requireSuperStart // nitpicking, but I’d like #requireSuperAtBeginning
actually better
  func mustCallSuperMethod() {
    // Some code
  }

}

class Subclass: Base {

  // All subclasses automatically (implicitly) inherit #requireSuperX,
this is visible across module boundaries
  override func mustCallSuperMethod() {
    // Do your setup
  }

}

The compiler would inject (invisible to the dev) the super() call at the
very beginning. The same is true for #requireSuperEnd.
I don’t think we need a #requireSuper because it means we don’t care when
it’s called so the compiler can decide where to put it.

The only problematic point might be a super call with arguments but I have
never ever changed the argument of a super call (e.g. in
viewDidAppear(animated: Bool) I never called the super implementation
other than super.viewDidAppear(animated)).

- Dennis, who is sick => please forgive any mistakes or oversights :pray:

On Feb 17, 2016, at 11:26 PM, Kyle Sherman via swift-evolution < > swift-evolution@swift.org> wrote:

Thanks for the replies.

Kenny: After thinking about it more, discussing with Peter, and looking
Haravikk’s comments, I think the best thing would be for this to be a
warning as suggested. I respectfully disagree that as a library creator you
would not be able to know that a call to super should be required. A
perfect example of this is the one stated in the proposal: viewDidLoad,
viewWillAppear, etc. In these cases, the library writers know that the
super version must be called and no matter what the subclasser does, they
will not be able to have correct behavior without calling super. This is
present in many places throughout the iOS SDK as example. In the static
analyzer in Xcode, for ObjC code, it warns when the developer doesn’t call
super in certain cases. Having these annotations would allow for developers
to specify this for their own code. Being able to suppress the warning
could also be a good feature, but I definitely don’t feel it would be
necessary for the implementation of the feature.

Haravikk: I don’t agree with using “(required)” as that will be a sort of
overloaded usage of the keyword. Also, I think that simply not specifying
anything would be a better way to go about it. So, @super would mean you
require the super method to be called, and simply not having an annotation
means that you do not have to call the super method. Peter and I have a
separate proposal that we will put up here soon for extending the
“required” keyword for all methods that I think will solve the problem of
abstract classes. I don’t think that we should conflate that issue, which
we feel is a separate issue, in with the issue of requiring the super
method to be called. Along the same lines, final by default was already
being discussed much earlier and I believe there was already a conclusion
to that saying it would not be implemented. I think the final keyword
should stay separate, especially since it is a compiler error vs this which
we are now saying would be a warning.

-Kyle

On Feb 17, 2016, at 12:31 PM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

Since this proposal is along the same lines as another current thread I’m
contributing to I’m of course very much for the basic functionality :wink:
From that other discussion my current preference is towards either an
attribute named @super, or allow the super keyword to be used in the method
declaration. So a declaration might look like:

@super(required)
func someMethod() { … }

Or (if you prefer):

super(required) func someMethod() { … }

The main ones needed are required and optional, with optional being what
we have now, and required simply ensuring that the super method is called
(no requirement on where). Options for before and after will be more useful
if we get abstract classes whose sole purpose is to be extended, as they
may have more specific requirements. The other possibly useful option would
@super(replace), in which case super may not be called by extending methods
at all, as it’s implementation may be very tightly coupled to the specific
implementation at that level, thus requiring a sub-class to re-implement
it; the parent method could also be some kind of stub for a feature it
doesn’t support, but which was required by a protocol for example.

Howard Lovatt also mentioned another interesting extension to the idea
which is that methods would effectively become final by default, requiring
a @super attribute if they are to be overridable, which I think would be
good for ensuring that only classes designed with extension in mind can
actually be extended. For this reason the @super attribute could also be
used on a class to set a new default for all methods. If we go with this
aspect then the final keyword would probably be moved into the @super
attribute for methods (properties would still have access to it though I
think).

On 17 Feb 2016, at 19:55, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:

There is just no way to know what may be required by clients of a
framework when it comes time to write actual shipping code. To require
users to call super - and to even extend that to knowing whether they
should call super at the beginning or end of their methods is too
restrictive. If this feature were to go forward, I would limit it to a
warning. It may belong more in a linter.

A lot of people have reacted negatively to the idea of before and after
requirements, but I think it’s important to note that they’re unlikely to
be commonly added; in most cases it won’t matter when the super method is
called so required or optional should be used as appropriate. Before and
after requirements are more useful for abstract or abstract-style classes
that offer partial implementations specifically designed to be extended, in
which case the order may be more important. Most of the time the deciding
factor will be whether your method performs some kind of updates to cached
values, in which case it will be important that it is called; the
requirement can also be used to serve as a reminder to read the
documentation about how exactly the parent method should be used by
extending classes, if it has any more unusual caveats.

I’ve been using IntelliJ IDEA a lot lately, and they basically have a live
linter that they call “code inspections”. I like this a lot. It goes waaay
beyond compiler-level warnings to offering you suggestions to improve your
code, finding sections of duplicated code, anything under the sun. They
also allow you to suppress any individual warning by putting an @suppress
in your code. Maybe Swift could benefit from another layer like this in
general, where you could be warned about a lot of stuff, but not be locked
into it.

It could make sense to have an option for whether breaking a requirement
produces a warning or an error? For example @super(required, warn) will
warn the developer that they are going against the parent class’
requirement to include the super method, but won’t actually stop them from
doing so if they really want to. This could provide a useful middle-ground
between optional and required, plus if the code of the parent class isn’t
under your control it gives you a fallback until there’s an update if the
warning behaviour were the default, with @super(required, error) style
declarations for developers who really know what their parent class needs
from sub-classes.

It’s also worth considering that most code will be under your control, so
you’ll just need to tweak (or add) the requirements, in the latter case it
forces you to consider how that class may be extended which I think is a
good thing.

On Feb 17, 2016, at 10:02 AM, Kyle Sherman via swift-evolution < > swift-evolution@swift.org> wrote:

I just saw that there was a discussion started about this topic just
recently while I was developing this idea with my colleague Peter Livesey.
So, I figured I would submit this proposal for discussion.

The link to the original discussion is here:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html

The subject was: “Replace the override keyword by ‘extend’ and ‘replace’
or add an annotation like @SuppressSuperCall

-Kyle

# Enforcing Calling Super

* Proposal: [SE-NNNN](
https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md
)
* Author(s): [Swift Developer](https://github.com/swiftdev)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain
overridden methods to call the superclass’s version of the method. This
change would enforce that the subclass called the superclass's method in
its overridden version at compile time. Also, it would optionally enforce
that the superclass's version would be called before any other
implementation in the method (similar to initialization rules).

Swift-evolution thread: [link to the discussion thread for that proposal](
https://lists.swift.org/pipermail/swift-evolution)

## Motivation

A concrete example of the type of problem this solves can be taken from
simple iOS code. When creating a subclass of UIViewController, you often
need to override methods like viewDidLoad or viewWillAppear. You are
supposed to call super.viewDidLoad or super.viewWillAppear, respectively,
in your overridden implementation. If you don't, you will have undefined
behavior and run into issues. Of course, this type of situation can be
extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the
superclass's code and making a note in the documentation. Quite obviously
this can cause many issues as mistakes can be made by new developers quite
easily who didn't look at the documentation for the method or even seasoned
developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an annotation similar to
@available and @noescape in order to convey this information. Optionally,
the developer can also choose to specify that the super method must be
called as the first line or last line of the overridden method.

The compiler would use the information from the annotation to ensure that
any overridden version of the method must call super at the appropriate
time according to the information given in the annotation. The compiler
would also need to ensure that any method that was going to use this
annotation had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because
there is currently no way to enforce super being called in an overridden
method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
   @requiredSuper func foo1() { }

   @requiredSuper(start) func foo2() { }

   @requiredSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super
method, the compiler should display an error. The errors that should be
displayed should be similar to:
• Overridden method must call the superclass’s implementation
• Overridden method must call the superclass’s implementation as the first
line of the method.
• Overridden method must call the superclass’s implementation as the last
line of the method.
for the cases of `@requiredSuper`, `@requiredSuper(start)`, and
`@requiredSuper(end)` respectively.

The compiler would also need to display an error in this case where the
access control of the method is stricter than that of the class:

public class MyClass {
   @requiredSuper func foo() { }
}

The compiler should show an error, such as “A method using @requiredSuper
must have access control set to be at least as accessible as the class that
contains it”.

## Impact on existing code

Implementation of this feature by the developer is completely optional.
Therefore, existing code will be unaffected and no migration of code will
be necessary. However, when APIs are updated to use this new feature, some
code will not compile if the developer did not use the APIs correctly. This
should be a welcomed compilation error as it will result in less buggy code
at runtime. The impact of this change is similar to adding nullability
annotations to Objective-C.

It will be impossible to migrate code automatically, because this
information cannot be derived in any way aside from reading comments if and
only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

_______________________________________________
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


(Haravikk) #16

Note: I’ve changed the syntax to # because I think this is compiler-magic and as Chris mentioned the following in the property behavior thread:

Is it compiler magic though? To me compiler magic is something that the compiler does to change your code, for example testing for OS version lets you add code specific to that OS. This wouldn’t actually change anything, it’s really just a directive in how the method should be implemented, personally that puts it closer to attributes such as @warn_unused_result IMO. You cite the case of the property behaviours proposal, however that is a proposal that introduces custom code that the compiler would connect to your properties for you, so it’s undoubtedly compiler magic of a sort.

If we do go for the hash prefix though, I don’t think that we need #requireSuperStart etc., just a general #requireSuper would do with optional brackets to add more specific requirements as has been proposed with attributes and keywords. That said, I think #requireSuper may be the wrong term, unless your intention was to also have #optionalSuper and #warnSuper? Personally I think it’d be easier to just to #super(required, before, warn) or whatever, same as we’ve been discussing for attributes and keywords, as it groups everything into the one command; there should be no reason we can’t just use super for the naming either since it’s unambiguous (and actually it’s relevant).

The compiler would inject (invisible to the dev) the super() call at the very beginning. The same is true for #requireSuperEnd.
I don’t think we need a #requireSuper because it means we don’t care when it’s called so the compiler can decide where to put it.

Like others have said I think we should shy away from the compiler adding this for us, as it may introduce debugging issues if someone didn’t notice the requirements and the compiler just went and fulfilled them automatically. By encouraging/forcing the developer to actually add the call then the implementation is at least complete and self-contained in its own right. I suppose maybe this is why you favoured the hash prefix as it definitely would be compiler magic for these cases, but I think without auto-insertion it isn’t really compiler magic, certainly no more than visibility keywords are.

···

On 17 Feb 2016, at 23:56, Dennis Weissmann <dennis@dennisweissmann.me> wrote:


(Ben Rimmington) #17

You could mention the `objc_requires_super` attribute in your proposal.

<http://clang.llvm.org/docs/AttributeReference.html#objc-requires-super>

But I haven't found it used in Apple's frameworks.

-- Ben

···

On 23 Feb 2016, at 00:51, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

Here is an updated version of the proposal. If no one has any other comments. Please review and let me know, because I would like to submit it for a review after I get comments on this version.


(plx) #18

Thank you everyone for the feedback. I think that suppressing the warnings generated by this is something that Swift doesn’t support at all right now. Therefore, I think that if/when the ability to suppress warnings is added, it will work for this as well. I don’t think this proposal needs to say anything about being able to suppress the warning, because it would be done at the call site anyway.

@plx: Given the examples you provided and my thoughts above, I think in this case you would just see the warning and just need to ignore it, because you know that you are doing it correctly. I think that is probably best at this point. The real solution would be to really enforce that member variables are not mutated according to the start/end parameter, but I don’t think that is really necessary as the warning can be ignored in these cases.

I do understand your point, but at the same time I wouldn’t be able to really use this feature until either “local warning suppression” (as a general feature, e.g. a Swift form of `#pragma clang diagnostic push` and so on...) or call-site annotations (e.g. as could be used to say “this counts as super(begin)”).

This is a policy issue (e.g. a policy of “all checked-in code must compile w/out warnings”) and not really a language issue specific to this feature, but it’d still a blocker in (for me) in terms of actually making use of such annotations.

One thing I want to make explicit is that even if it’s just @requireSuper w/out the positional features, the closure example is problematic:

// assume @requireSuper has been added
override func layoutSubviews() {
  self.performMeasuredAction(“layout”) {
    super.layoutSubviews()
    self.layoutLocalSubviews()
  }
}

…does `performMeasuredAction` actually call that closure?

How would the compiler know?

Anyways I think even the most basic version of a feature like this is a win, but practically-speaking it’s a win I may not be able to use in general w/out a corresponding feature to annotate call sites (or locally suppress warnings, etc.).

···

On Feb 22, 2016, at 6:51 PM, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

@haravikk: I still don’t see a reason to have a parameter for saying that it is required, since as we both agreed, it makes sense that only when the attribute is defined, is it required. Having the attribute declared but not have required would basically be invalid. I think baking it into the name like I originally suggested is probably best, as @super by itself is probably not explicit enough. The naming of these attributes and casing are being debated in a different thread, so I think I will just submit my suggestion with the idea that it can be corrected to fit what they decide in the other thread.

Here is an updated version of the proposal. If no one has any other comments. Please review and let me know, because I would like to submit it for a review after I get comments on this version.

# Enforcing Calling Super

* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
* Author(s): [Kyle Sherman](https://github.com/drumnkyle)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called either before any other implementation in the method (similar to initialization rules) or as the last line in the method.

Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010509.html)

## Motivation

A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.

Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.

## Proposed solution

The solution proposed here would be to use an attribute similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.

The compiler would use the information from the attribute to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the attribute. The compiler would also need to ensure that any method that was going to use this attribute had the same access control level as the class that contains it.

This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiresSuper func foo1() { }

    @requiresSuper(start) func foo2() { }

    @requiresSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display a warning. The warnings that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiresSuper`, `@requiresSuper(start)`, and `@requiresSuper(end)` respectively.

The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:

public class MyClass {
    @requiresSuper func foo() { }
}

The compiler should show a warning, such as “A method using @requiresSuper must have access control set to be at least as accessible as the class that contains it”.

There can also be a simple fix-it that adds in the call to the super’s method. The specifics of the exact name and syntax is flexible as long as it has the 3 features proposed and produces a warning.

## Impact on existing code

The good thing about this change is that it will not have any impact on existing Swift code. This is an optional attribute provided by the developer. Therefore, if the attribute is not used, nothing is changed.

Unfortunately, there is no good way to automatically migrate code to use this new attribute, because the information would have only been embedded in comments previously. Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability attributes to Objective-C.

It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.

## Alternatives considered

The alternative would simply be to not implement this feature.

> I hope we will be able to use something like the clang diagnostic macro's to do that...
>
> Sent from my iPhone
>
> On 18 Feb 2016, at 15:02, plx via swift-evolution<swift-evolution@swift.org <mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>)>wrote:
>
> > I think something like this making it into Swift at some point would be great, even if it’s just the `@requiresSuper` form; the positional variants would be even better.
> >
> > However, I think any proposal like this will be *unusable* unless it *also* includes some way of explicitly marking a specific super-call as “OK, despite how it looks!”…and this is true even if you spec the feature out to only produce warnings, b/c even then you may want to silence those warnings at specific, “known-no-problem” call sites.
> >
> > Here are two concrete examples:
> >
> > // suppose `updateConstraints` has `@super(end)` applied to it:
> > override func updateConstraints() {
> > // figure out where a bug is coming from:
> > debugLog(“<ISSUE 124>#before constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> > debugLog(“<ISSUE 124>#beforeconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> > self.updateMyLocalConstraints()
> > debugLog(“<ISSUE 124>#after constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> > debugLog(“<ISSUE 124>#afterconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> > super.updateConstraints() //<- not last call, but actually ok
> > debugLog(“<ISSUE 124>#final constraints.horizontal: \(self.constraintsAffectingLayoutForAxis(.Horizontal))”)
> > debugLog(“<ISSUE 124>#finalconstraints.vertical: \(self.constraintsAffectingLayoutForAxis(.Vertical))”)
> > }
> >
> > // suppose `layoutSubviews` has `@super(begin)` applied to it:
> > override func layoutSubviews() {
> > // capture timing info in debug runs:
> > #if DEBUG
> > self.performTimedBlock(“updateConstraints”) {
> > super.layoutSubviews() //<- not “first call”, but actually ok
> > self.layoutMyCustomSubviews()
> > }
> > #else
> > super.layoutSubviews()
> > self.layoutMyCustomSubviews()
> > #endif
> > }
> >
> > …and I picked these because they’re examples where we are actually obeying the “spirit" of the @super annotation.
> >
> > Such an annotation could either be applied to the method (something like: `@force(@super(end):true)`?), or perhaps an annotation applied to the specific call-site…but right now, I don’t think Swift has anything at all that uses a "call-site” attribute.
> >
> > Are there any?
> >
> > > On Feb 17, 2016, at 12:02 PM, Kyle Sherman via swift-evolution<swift-evolution@swift.org <mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>)>wrote:
> > > I just saw that there was a discussion started about this topic just recently while I was developing this idea with my colleague Peter Livesey. So, I figured I would submit this proposal for discussion.
> > >
> > > The link to the original discussion is here:https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html <http://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html>
> > >
> > > The subject was: “Replace the override keyword by ‘extend’ and ‘replace’ or add an annotation like @SuppressSuperCall
> > >
> > > -Kyle
> > >
> > > # Enforcing Calling Super
> > >
> > > * Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md)
> > > * Author(s): [Swift Developer](https://github.com/swiftdev)
> > > * Status: **Awaiting review**
> > > * Review manager: TBD
> > >
> > > ## Introduction
> > >
> > > Many times when creating a subclass the superclass has reasons for certain overridden methods to call the superclass’s version of the method. This change would enforce that the subclass called the superclass's method in its overridden version at compile time. Also, it would optionally enforce that the superclass's version would be called before any other implementation in the method (similar to initialization rules).
> > >
> > > Swift-evolution thread: [link to the discussion thread for that proposal](https://lists.swift.org/pipermail/swift-evolution)
> > >
> > > ## Motivation
> > >
> > > A concrete example of the type of problem this solves can be taken from simple iOS code. When creating a subclass of UIViewController, you often need to override methods like viewDidLoad or viewWillAppear. You are supposed to call super.viewDidLoad or super.viewWillAppear, respectively, in your overridden implementation. If you don't, you will have undefined behavior and run into issues. Of course, this type of situation can be extrapolated to any class created in Swift.
> > > Currently, the only way this can be enforced is by commenting the superclass's code and making a note in the documentation. Quite obviously this can cause many issues as mistakes can be made by new developers quite easily who didn't look at the documentation for the method or even seasoned developers who simply overlooked this small detail.
> > > ## Proposed solution
> > >
> > > The solution proposed here would be to use an annotation similar to @available and @noescape in order to convey this information. Optionally, the developer can also choose to specify that the super method must be called as the first line or last line of the overridden method.
> > > The compiler would use the information from the annotation to ensure that any overridden version of the method must call super at the appropriate time according to the information given in the annotation. The compiler would also need to ensure that any method that was going to use this annotation had the same access control level as the class that contains it.
> > > This solution will be much safer than what is currently available, because there is currently no way to enforce super being called in an overridden method. This bug happens constantly for iOS developers.
> > >
> > > ## Detailed design
> > >
> > > A possible implementation of this may look like this:
> > > ```
> > > class MyClass {
> > > @requiredSuper func foo1() { }
> > >
> > > @requiredSuper(start) func foo2() { }
> > > @requiredSuper(end) func foo3() { }
> > > }
> > > ```
> > >
> > > Now, if the developer were to create a subclass and not call the super method, the compiler should display an error. The errors that should be displayed should be similar to:
> > > Overridden method must call the superclass’s implementation
> > >
> > > Overridden method must call the superclass’s implementation as the first line of the method.
> > >
> > > Overridden method must call the superclass’s implementation as the last line of the method.
> > >
> > >
> > > for the cases of `@requiredSuper`, `@requiredSuper(start)`, and `@requiredSuper(end)` respectively.
> > >
> > > The compiler would also need to display an error in this case where the access control of the method is stricter than that of the class:
> > > ```
> > > public class MyClass {
> > > @requiredSuper func foo() { }
> > > }
> > > ```
> > >
> > > The compiler should show an error, such as “A method using @requiredSuper must have access control set to be at least as accessible as the class that contains it”.
> > >
> > > ## Impact on existing code
> > >
> > > Implementation of this feature by the developer is completely optional. Therefore, existing code will be unaffected and no migration of code will be necessary. However, when APIs are updated to use this new feature, some code will not compile if the developer did not use the APIs correctly. This should be a welcomed compilation error as it will result in less buggy code at runtime. The impact of this change is similar to adding nullability annotations to Objective-C.
> > > It will be impossible to migrate code automatically, because this information cannot be derived in any way aside from reading comments if and only if the API author documented it.
> > >
> > > ## Alternatives considered
> > > The alternative would simply be to not implement this feature.
> > >
> > > _______________________________________________
> > > swift-evolution mailing list
> > > swift-evolution@swift.org <mailto:swift-evolution@swift.org>(mailto: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>(mailto: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


(Haravikk) #19

My reasoning was that it may make sense to have a distinction between required and other restriction types, for example:

optional: super call can be included if desired (this is the default, but IMO before/after should default to being requirements, so this would be useful for changing that).
required: super call *must* be included or an error is produced
warn: downgrades errors to warnings, implies required by default (i.e- super call *should* be included or a warning is produced)
replace: super call should not be included or an error is produced (i.e- the requirement is that overriding methods must be a total replacement)

While the proposal doesn’t have to push for these up front, I think that they still make sense as possible extensions of the feature, and adding @warnSuper, @optionalSuper etc. would make things more unwieldy. But the added flexibility would be very useful, for example:

  @super(optional, before) // super call isn’t required, but if it is included it must come first.
  @super(replace, warn) // downgrades replace to a warning, so a developer can still use the super call if they like, but should be very sure they know what they’re doing.

Personally I think @super is clear enough, though @includeSuper or such may be more-so. I just think that @requireSuper is too specific, especially if the default for the proposal is to generate a warning, since as mentioned we may want to push an error if we know that our parent class will break horribly if its method(s) aren’t called.

···

On 23 Feb 2016, at 00:51, Kyle Sherman via swift-evolution <swift-evolution@swift.org> wrote:

@haravikk: I still don’t see a reason to have a parameter for saying that it is required, since as we both agreed, it makes sense that only when the attribute is defined, is it required. Having the attribute declared but not have required would basically be invalid. I think baking it into the name like I originally suggested is probably best, as @super by itself is probably not explicit enough. The naming of these attributes and casing are being debated in a different thread, so I think I will just submit my suggestion with the idea that it can be corrected to fit what they decide in the other thread.


#20

Been following the many discussions on this topic and I do not think that these start/end requirements will ever fly. Imposing such a specific location on the sub-classes will cause a lot of troubles, whether it being unable to add debug log, or to tweak parameters before passing them to super, in the end the developer of the main class won’t dare use such specification, to avoid pushing away potential sub-class developer, and as a way to preemptively mute their complaining.

OTOH, my guts are telling me that, some similar form of control may be desired on some occasion mainly when playing with resources, maybe for a setup-like method where super should be call before any other methods provided by the class, and or for close-like method, the reverse. Unfortunately, unless such rules are made rigid (all or nothing) such syntax would likely be too convoluted and long; super.close() must be call after super.read(), super.write(), ...

A possible syntax for the rigid rules would be:

@requiresSuper(before: methods)
@requiresSuper(after: methods, propertiesSetter)
@requiresSuper(before: methods, propertiesGetter)

But, I do not have any examples in mind to corroborate that such options are better than the proposed @requiresSuper(start) and @requiresSuper(end). IMHO, I just think that @requiresSuper(start) and @requiresSuper(end) should be drop as too intransigent, which will cause them to be rarely used.

Dany

···

Le 22 févr. 2016 à 19:51, Kyle Sherman via swift-evolution <swift-evolution@swift.org> a écrit :

## Detailed design

A possible implementation of this may look like this:

class MyClass {
    @requiresSuper func foo1() { }

    @requiresSuper(start) func foo2() { }

    @requiresSuper(end) func foo3() { }
}

Now, if the developer were to create a subclass and not call the super method, the compiler should display a warning. The warnings that should be displayed should be similar to:
Overridden method must call the superclass’s implementation
Overridden method must call the superclass’s implementation as the first line of the method.
Overridden method must call the superclass’s implementation as the last line of the method.
for the cases of `@requiresSuper`, `@requiresSuper(start)`, and `@requiresSuper(end)` respectively.