[Discussion] Enforcing Calling Super


(Jeremy W. Sherman) #1

Ah bother, the list doesn't default reply-to to the list? (Or iOS mail doesn't respect the header.)

···

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

Inicio del mensaje reenviado:

De: "Jeremy W. Sherman" <jeremyw.sherman@gmail.com>
Fecha: 1 de marzo de 2016, 10:30:05 GMT-5
Para: Kyle Sherman <kyledsherman@gmail.com>
Asunto: Re: [swift-evolution] [Discussion] Enforcing Calling Super

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.
--
Jeremy W. Sherman
http://jeremywsherman.com/

El 17-02-2016, a las 13:02, 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:
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


(Kyle Sherman) #2

Great catch Jeremy. I'm not sure how the availability API works with other annotations. Does anyone know if this is possible?

···

On Mar 1, 2016, at 7:31 AM, Jeremy W. Sherman via swift-evolution <swift-evolution@swift.org> wrote:

Ah bother, the list doesn't default reply-to to the list? (Or iOS mail doesn't respect the header.)
--
Jeremy W. Sherman
http://jeremywsherman.com/

Inicio del mensaje reenviado:

De: "Jeremy W. Sherman" <jeremyw.sherman@gmail.com <mailto:jeremyw.sherman@gmail.com>>
Fecha: 1 de marzo de 2016, 10:30:05 GMT-5
Para: Kyle Sherman <kyledsherman@gmail.com <mailto:kyledsherman@gmail.com>>
Asunto: Re: [swift-evolution] [Discussion] Enforcing Calling Super

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.
--
Jeremy W. Sherman
http://jeremywsherman.com/

El 17-02-2016, a las 13:02, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto: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:
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


(Kyle Sherman) #3

This has gone off of the original thread. Jeremy: can you try replying to directly to the main thread and saying the same thing you said in your original email?

If you have any questions about doing this, email me directly.

···

Ah bother, the list doesn't default reply-to to the list? (Or iOS mail doesn't respect the header.)
--
Jeremy W. Sherman
http://jeremywsherman.com/

Inicio del mensaje reenviado:

> De:"Jeremy W. Sherman"<jeremyw.sherman@gmail.com(mailto:jeremyw.sherman@gmail.com)>
> Fecha:1 de marzo de 2016, 10:30:05 GMT-5
> Para:Kyle Sherman<kyledsherman@gmail.com(mailto:kyledsherman@gmail.com)>
> Asunto:Re: [swift-evolution] [Discussion] Enforcing Calling Super
>
> 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.
> --
> Jeremy W. Sherman
> http://jeremywsherman.com/
>
>
> El 17-02-2016, a las 13:02, Kyle Sherman via swift-evolution<swift-evolution@swift.org(mailto: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:
> > 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