[Discussion] Enforcing Calling Super

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

···

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> a écrit :

On 17 Feb 2016, at 22:26, 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.

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?

Because the parent class told you not to? I’ve said repeatedly on the subject now however that before/after constraints aren’t something that you should expect to see commonly, as they’re something that developers should only set if they are absolutely certain that they will be required. The way I see it they will be most commonly used in two particular cases:

Partial Implementation: For an abstract-style class, a provided partial implementation might only handle the preliminary setup or final handling of values, in which case it must be called first or last in order for an implementation to be completing it correctly.
Undefined State: If the parent class shares values and methods for sub-classes to use, but cannot guarantee a consistent state if they are called without the super method. Again this is really more likely to happen in types that are specifically intended for extension where order may be important, rather than a complete type that you just happen to decide to extend.

To reiterate, these should one of the less commonly used operations, and since the default is going to be to issue a warning then you aren’t prevented from doing anything.

It’s also possible that if the compiler can better detect “mutating” class methods then it would be possible for it to allow non-mutating code in front of a before condition, though could still potentially need to be warned against (in the undefined state you could be retrieving a value before it’s ready to be used). But once again, it’ll be a warning, so you can just ignore, and that’s assuming the condition is even being used, which shouldn’t be very common if it’s being used sensibly.

···

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

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 think your suggestion is structured, flexible, and entirely optional. Like it a lot because it would allow code to be even more expressive.

···

Sent from my iPhone

On 18 Feb 2016, at 09:00, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

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 ;-)
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: [swift-evolution] Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall

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

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

Good call Ben! I never knew about that. Seems like maybe Apple even forgot about it. Lol

···

Sent from my iPhone

On Feb 22, 2016, at 5:14 PM, Ben Rimmington <me@benrimmington.com> wrote:

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.

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

<Attributes in Clang — Clang 18.0.0git documentation;

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

-- Ben

Foundation.h wraps it as NS_REQUIRES_SUPER. That spelling is used in most places. There was no deliberate effort to annotate old API so it is likely that many potential uses were not updated.

···

On Feb 22, 2016, at 5:14 PM, Ben Rimmington via swift-evolution <swift-evolution@swift.org> wrote:

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.

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

<Attributes in Clang — Clang 18.0.0git documentation;

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

--
Greg Parker gparker@apple.com Runtime Wrangler

My 5c on this topic: I would be ok with adding a directive like @requiredSuper (even though I am afraid it will be abused). However, I am very much agains any more precise annotations or implicit super calls. I do not think it adds much utility to the language, however it most certainly allows more ways to mess with the users of your library.

Best,

Taras

···

On 23 Feb 2016, at 10:02, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 23 Feb 2016, at 00:51, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto: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.

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

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?

I think that what was discussed under Guaranteed closure execution (aka @noescape(once)) (https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md\) could be able to detect that the super requirement is met in this particular scenario.

Dany

···

Le 23 févr. 2016 à 09:18, plx via swift-evolution <swift-evolution@swift.org> a écrit :

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

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.).

@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:[swift-evolution] Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall <http://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160215/010310.html&gt;
> > >
> > > 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 <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

I mentioned in the previous discussion that before/after shouldn’t really be used in a general sense right now, but when we get abstract classes they will make a lot more sense depending upon what aspect of a type an abstract method actually implements. They shouldn’t be all that common, but when you’re absolutely certain that they’re need then they are important; for example if a parent class could be in an inconsistent state if its super method isn’t called first (meaning any other methods it implements could give undefined results if also used within the child class).

There are definitely use cases for these requirements, they just aren’t the most common, so shouldn’t be placed as restrictions unless you know you absolutely need them. That said, this is partly why the proposals seem to be erring toward issuing a warning as the default behaviour, as this means that a developer can still just ignore it and do what they like anyway, albeit accepting the risks it may involve.

Regarding putting things before the super call such as debug logs and parameter tweaks; this could still be possible if we can think of a good way to handle them, i.e- anything non-mutating could be fine, but the question is how to detect that; I’m not sure if adding such detection is worth the effort to allow niche usage around a niche requirement which, as a warning, you can just ignore anyway.

···

On 24 Feb 2016, at 02:07, Dany St-Amant via swift-evolution <swift-evolution@swift.org> wrote:

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.

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?

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about this. You might want to look for that message in the archives.

···

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> a écrit :

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

And not a single one has a strong requirement about prohibiting code to be call before or after the super class implementation.

···

Le 25 févr. 2016 à 20:19, Matthew Johnson via swift-evolution <swift-evolution@swift.org> a écrit :

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> a écrit :

On 17 Feb 2016, at 22:26, 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.

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?

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about this. You might want to look for that message in the archives.

I keep seeing the argument made that people can just ignore warnings so it does not stop them. I think that is a misuse of warnings. We should not be providing warnings that we expect some people to just ignore. Further, at many places warnings are treated the same as errors.

- Step

···

On Feb 25, 2016, at 5:02 PM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

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?

Because the parent class told you not to? I’ve said repeatedly on the subject now however that before/after constraints aren’t something that you should expect to see commonly, as they’re something that developers should only set if they are absolutely certain that they will be required. The way I see it they will be most commonly used in two particular cases:

Partial Implementation: For an abstract-style class, a provided partial implementation might only handle the preliminary setup or final handling of values, in which case it must be called first or last in order for an implementation to be completing it correctly.
Undefined State: If the parent class shares values and methods for sub-classes to use, but cannot guarantee a consistent state if they are called without the super method. Again this is really more likely to happen in types that are specifically intended for extension where order may be important, rather than a complete type that you just happen to decide to extend.

To reiterate, these should one of the less commonly used operations, and since the default is going to be to issue a warning then you aren’t prevented from doing anything.

It’s also possible that if the compiler can better detect “mutating” class methods then it would be possible for it to allow non-mutating code in front of a before condition, though could still potentially need to be warned against (in the undefined state you could be retrieving a value before it’s ready to be used). But once again, it’ll be a warning, so you can just ignore, and that’s assuming the condition is even being used, which shouldn’t be very common if it’s being used sensibly.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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?

Because the parent class told you not to?

And what right does the parent class have to tell me not to?

I’ve said repeatedly on the subject now however that before/after constraints aren’t something that you should expect to see commonly,

Before and after constraints should never be seen. How can the designer of the superclass possibly know what code is safe in front of the call to super and what isn’t?

as they’re something that developers should only set if they are absolutely certain that they will be required. The way I see it they will be most commonly used in two particular cases:

  • Partial Implementation: For an abstract-style class, a provided partial implementation might only handle the preliminary setup or final handling of values, in which case it must be called first or last in order for an implementation to be completing it correctly.

And what if I want to put a log message in front of the call?

  • Undefined State: If the parent class shares values and methods for sub-classes to use, but cannot guarantee a consistent state if they are called without the super method. Again this is really more likely to happen in types that are specifically intended for extension where order may be important, rather than a complete type that you just happen to decide to extend.

I think I would design my superclass better so that this situation doesn’t arise.

···

On 25 Feb 2016, at 23:02, Haravikk <swift-evolution@haravikk.me> wrote:

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

It depends what you mean by “strong”. Sure, a log statement won’t make much difference. But the examples I gave do have semantic requirements that super should either go first or last in performing real work to be done by the method.

···

On Feb 25, 2016, at 1:23 PM, Jean-Daniel Dupas <mailing@xenonium.com> wrote:

Le 25 févr. 2016 à 20:19, Matthew Johnson via swift-evolution <swift-evolution@swift.org> a écrit :

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> a écrit :

On 17 Feb 2016, at 22:26, 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.

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?

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about this. You might want to look for that message in the archives.

And not a single one has a strong requirement about prohibiting code to be call before or after the super class implementation.

For instance:
// If you override this method, you must call super first to get the invalidation context object to return. After getting this object, set any custom properties and return it.
func invalidationContextForBoundsChange(_ newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext

Why must I call super first ? Why can’t I don’t a bunch of things that are related to my subclass first ?

How am I supposed to do if I want to compute a new bound to pass to super instead of forwarding it naively.

ditto for
// call super first to retrieve the item’s existing attributes and then make your changes to the returned structure.
layoutAttributesForInteractivelyMovingItemAtIndexPath(_ indexPath: NSIndexPath, withTargetPosition position: CGPoint) -> UICollectionViewLayoutAttributes
Why would you prevent a subclass to compute an other indexPath or target position before calling super ?

···

Le 25 févr. 2016 à 20:28, Matthew Johnson <matthew@anandabits.com> a écrit :

On Feb 25, 2016, at 1:23 PM, Jean-Daniel Dupas <mailing@xenonium.com <mailto:mailing@xenonium.com>> wrote:

Le 25 févr. 2016 à 20:19, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On 17 Feb 2016, at 22:26, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto: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.

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?

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about this. You might want to look for that message in the archives.

And not a single one has a strong requirement about prohibiting code to be call before or after the super class implementation.

It depends what you mean by “strong”. Sure, a log statement won’t make much difference. But the examples I gave do have semantic requirements that super should either go first or last in performing real work to be done by the method.

@Step: I agree with you. I just cannot ignore a single warning and I'm not
happy until my project compiles without errors *and* without any warnings.

-Van

···

On Fri, Feb 26, 2016 at 10:28 AM, Step C via swift-evolution < swift-evolution@swift.org> wrote:

I keep seeing the argument made that people can just ignore warnings so it
does not stop them. I think that is a misuse of warnings. We should not be
providing warnings that we expect some people to just ignore. Further, at
many places warnings are treated the same as errors.

- Step

On Feb 25, 2016, at 5:02 PM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution < > swift-evolution@swift.org> wrote:

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?

Because the parent class told you not to? I’ve said repeatedly on the
subject now however that before/after constraints aren’t something that you
should expect to see commonly, as they’re something that developers should
only set if they are absolutely certain that they will be required. The way
I see it they will be most commonly used in two particular cases:

   - *Partial Implementation:* For an abstract-style class, a provided
   partial implementation might only handle the preliminary setup or final
   handling of values, in which case it must be called first or last in order
   for an implementation to be completing it correctly.
   - *Undefined State:* If the parent class shares values and methods for
   sub-classes to use, but cannot guarantee a consistent state if they are
   called without the super method. Again this is really more likely to happen
   in types that are specifically intended for extension where order may be
   important, rather than a complete type that you just happen to decide to
   extend.

To reiterate, these should one of the less commonly used operations, and
since the default is going to be to issue a warning then *you aren’t
prevented from doing anything*.

It’s also possible that if the compiler can better detect “mutating” class
methods then it would be possible for it to allow non-mutating code in
front of a before condition, though could still potentially need to be
warned against (in the undefined state you could be retrieving a value
before it’s ready to be used). But once again, it’ll be a warning, so you
can just ignore, and that’s assuming the condition is even being used,
which shouldn’t be very common if it’s being used sensibly.

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

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

I'm convinced that we shouldn't add the begin/end functionality to this proposal. So, I will remove that from the proposal, add in reference to the NS_REQUIRES_SUPER macro, and post the final proposal for review.

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?

Because the parent class told you not to?

And what right does the parent class have to tell me not to?

I’ve said repeatedly on the subject now however that before/after constraints aren’t something that you should expect to see commonly,

Before and after constraints should never be seen. How can the designer of the superclass possibly know what code is safe in front of the call to super and what isn’t?

as they’re something that developers should only set if they are absolutely certain that they will be required. The way I see it they will be most commonly used in two particular cases:

   • Partial Implementation: For an abstract-style class, a provided partial implementation might only handle the preliminary setup or final handling of values, in which case it must be called first or last in order for an implementation to be completing it correctly.

And what if I want to put a log message in front of the call?

   • Undefined State: If the parent class shares values and methods for sub-classes to use, but cannot guarantee a consistent state if they are called without the super method. Again this is really more likely to happen in types that are specifically intended for extension where order may be important, rather than a complete type that you just happen to decide to extend.

I think I would design my superclass better so that this situation doesn’t arise.

···

Sent from my iPhone
On Feb 29, 2016, at 8:01 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 25 Feb 2016, at 23:02, Haravikk <swift-evolution@haravikk.me> wrote:

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

I vote (again) to only specify if a func requires super. When to call super
is up to the developer after reading the docs.

-Van

···

On Thu, Feb 25, 2016 at 5:02 PM, Jean-Daniel Dupas via swift-evolution < swift-evolution@swift.org> wrote:

Le 25 févr. 2016 à 20:28, Matthew Johnson <matthew@anandabits.com> a
écrit :

On Feb 25, 2016, at 1:23 PM, Jean-Daniel Dupas <mailing@xenonium.com> > wrote:

Le 25 févr. 2016 à 20:19, Matthew Johnson via swift-evolution < > swift-evolution@swift.org> a écrit :

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution < > swift-evolution@swift.org> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution < > swift-evolution@swift.org> a écrit :

On 17 Feb 2016, at 22:26, 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.

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?

+1 with your concern. I’d be curious to see a single real world use case
where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about
this. You might want to look for that message in the archives.

And not a single one has a strong requirement about prohibiting code to be
call before or after the super class implementation.

It depends what you mean by “strong”. Sure, a log statement won’t make
much difference. But the examples I gave do have semantic requirements
that super should either go first or last in performing real work to be
done by the method.

For instance:

// If you override this method, you must call super first to get the invalidation context object to return. After getting this object, set any custom properties and return it.
func invalidationContextForBoundsChange(_ newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext

Why must I call super first ? Why can’t I don’t a bunch of things that are
related to my subclass first ?

How am I supposed to do if I want to compute a new bound to pass to super
instead of forwarding it naively.

ditto for

// call super first to retrieve the item’s existing attributes and then make your changes to the returned structure.
layoutAttributesForInteractivelyMovingItemAtIndexPath(_ indexPath: NSIndexPath, withTargetPosition position: CGPoint) -> UICollectionViewLayoutAttributes

Why would you prevent a subclass to compute an other indexPath or target
position before calling super ?

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

I agree.

While there may be specific cases where super must be called first or last, I think the examples provided were exceptions, rather than rules. The dealloc method in Obj-C for example was one case, and it was so overarching that the compiler took control of that with ARC.

I fail to see in mainstream code why it would ever be necessary to force a programmer not to do a single line of work prior, or prior to the end of, a super call. Could there be exceptions? I’m sure we could eventually find a use case. But I don’t think this is prolific enough that we need to start adding to the language for it. We can document the requirement on the method if we need to.

···

On 26 Feb 2016, at 7:38 AM, Vanderlei Martinelli via swift-evolution <swift-evolution@swift.org> wrote:

I vote (again) to only specify if a func requires super. When to call super is up to the developer after reading the docs.

-Van

On Thu, Feb 25, 2016 at 5:02 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Le 25 févr. 2016 à 20:28, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> a écrit :

On Feb 25, 2016, at 1:23 PM, Jean-Daniel Dupas <mailing@xenonium.com <mailto:mailing@xenonium.com>> wrote:

Le 25 févr. 2016 à 20:19, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Sent from my iPad

On Feb 25, 2016, at 1:17 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Le 25 févr. 2016 à 16:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On 17 Feb 2016, at 22:26, Kyle Sherman via swift-evolution <swift-evolution@swift.org <mailto: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.

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?

+1 with your concern. I’d be curious to see a single real world use case where enforcing first or last is required.

I posted several examples from Apple frameworks in an old thread about this. You might want to look for that message in the archives.

And not a single one has a strong requirement about prohibiting code to be call before or after the super class implementation.

It depends what you mean by “strong”. Sure, a log statement won’t make much difference. But the examples I gave do have semantic requirements that super should either go first or last in performing real work to be done by the method.

For instance:
// If you override this method, you must call super first to get the invalidation context object to return. After getting this object, set any custom properties and return it.
func invalidationContextForBoundsChange(_ newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext

Why must I call super first ? Why can’t I don’t a bunch of things that are related to my subclass first ?

How am I supposed to do if I want to compute a new bound to pass to super instead of forwarding it naively.

ditto for
// call super first to retrieve the item’s existing attributes and then make your changes to the returned structure.
layoutAttributesForInteractivelyMovingItemAtIndexPath(_ indexPath: NSIndexPath, withTargetPosition position: CGPoint) -> UICollectionViewLayoutAttributes
Why would you prevent a subclass to compute an other indexPath or target position before calling super ?

_______________________________________________
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

+1, and I would add that I don’t consider adding a "silence warning" attribute a valid solution to avoid a warning.

···

Le 26 févr. 2016 à 16:50, Vanderlei Martinelli via swift-evolution <swift-evolution@swift.org> a écrit :

@Step: I agree with you. I just cannot ignore a single warning and I'm not happy until my project compiles without errors *and* without any warnings.

-Van

On Fri, Feb 26, 2016 at 10:28 AM, Step C via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I keep seeing the argument made that people can just ignore warnings so it does not stop them. I think that is a misuse of warnings. We should not be providing warnings that we expect some people to just ignore. Further, at many places warnings are treated the same as errors.

- Step

On Feb 25, 2016, at 5:02 PM, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 25 Feb 2016, at 15:47, Jeremy Pereira via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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?

Because the parent class told you not to? I’ve said repeatedly on the subject now however that before/after constraints aren’t something that you should expect to see commonly, as they’re something that developers should only set if they are absolutely certain that they will be required. The way I see it they will be most commonly used in two particular cases:

Partial Implementation: For an abstract-style class, a provided partial implementation might only handle the preliminary setup or final handling of values, in which case it must be called first or last in order for an implementation to be completing it correctly.
Undefined State: If the parent class shares values and methods for sub-classes to use, but cannot guarantee a consistent state if they are called without the super method. Again this is really more likely to happen in types that are specifically intended for extension where order may be important, rather than a complete type that you just happen to decide to extend.

To reiterate, these should one of the less commonly used operations, and since the default is going to be to issue a warning then you aren’t prevented from doing anything.

It’s also possible that if the compiler can better detect “mutating” class methods then it would be possible for it to allow non-mutating code in front of a before condition, though could still potentially need to be warned against (in the undefined state you could be retrieving a value before it’s ready to be used). But once again, it’ll be a warning, so you can just ignore, and that’s assuming the condition is even being used, which shouldn’t be very common if it’s being used sensibly.
_______________________________________________
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