Add code to super methods.


(Mustafa Sabur) #1

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
  override func viewDidLoad() {
    super.viewDidLoad()
    // Your code
  }

Suggestion:
  addinto func viewDidLoad() {
    // Your code
  }

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
    This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur


(Sean Heber) #2

That could be kind of neat - perhaps a syntax more like this so that there isn’t another bare keyword:

override(after) func viewDidLoad() {
}

and:

override(before) func viewDidLoad() {
}

Which would allow you to specify where your code happens - either before or after the superclass method, essentially. Leaving out before/after would still behave as expected and you’d have to call super yourself (or not):

override func viewDidLoad() {
  // stuff
  super.viewDidLoad()
  // more stuff
}

A potentially neat thing about this is that you could possibly then impose restrictions on subclasses like so:

final(before) func viewDidLoad() {}

Which could mean that the “before” slot is “final” - therefore you cannot do either of these:

override func viewDidLoad() {}
override(before) func viewDidLoad() {}

l8r
Sean

···

On Nov 16, 2016, at 4:30 PM, Mustafa Sabur via swift-evolution <swift-evolution@swift.org> wrote:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
  override func viewDidLoad() {
    super.viewDidLoad()
    // Your code
  }

Suggestion:
  addinto func viewDidLoad() {
    // Your code
  }

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
    This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Sean Heber) #3

All that said, there is a slight flaw here which is - what happens if you want to alter the input to super’s method in your override? That might be a deal-breaker.

l8r
Sean

···

On Nov 16, 2016, at 4:37 PM, Sean Heber <sean@fifthace.com> wrote:

That could be kind of neat - perhaps a syntax more like this so that there isn’t another bare keyword:

override(after) func viewDidLoad() {
}

and:

override(before) func viewDidLoad() {
}

Which would allow you to specify where your code happens - either before or after the superclass method, essentially. Leaving out before/after would still behave as expected and you’d have to call super yourself (or not):

override func viewDidLoad() {
// stuff
super.viewDidLoad()
// more stuff
}

A potentially neat thing about this is that you could possibly then impose restrictions on subclasses like so:

final(before) func viewDidLoad() {}

Which could mean that the “before” slot is “final” - therefore you cannot do either of these:

override func viewDidLoad() {}
override(before) func viewDidLoad() {}

l8r
Sean

On Nov 16, 2016, at 4:30 PM, Mustafa Sabur via swift-evolution <swift-evolution@swift.org> wrote:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
  override func viewDidLoad() {
    super.viewDidLoad()
    // Your code
  }

Suggestion:
  addinto func viewDidLoad() {
    // Your code
  }

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
   This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Javier Soto) #4

This has been discussed a few times already. As far as I can remember, the
major takeaways were:

- Often APIs want you to call super either before or after your
implementation, so we would need syntax for that too
- Protocols and composition are often a much better way to model this, as
opposed to relying on things like the method call ordering.

All that said, there is a slight flaw here which is - what happens if you
want to alter the input to super’s method in your override? That might be a
deal-breaker.

l8r
Sean

That could be kind of neat - perhaps a syntax more like this so that

there isn’t another bare keyword:

override(after) func viewDidLoad() {
}

and:

override(before) func viewDidLoad() {
}

Which would allow you to specify where your code happens - either before

or after the superclass method, essentially. Leaving out before/after would
still behave as expected and you’d have to call super yourself (or not):

override func viewDidLoad() {
// stuff
super.viewDidLoad()
// more stuff
}

A potentially neat thing about this is that you could possibly then

impose restrictions on subclasses like so:

final(before) func viewDidLoad() {}

Which could mean that the “before” slot is “final” - therefore you cannot

do either of these:

override func viewDidLoad() {}
override(before) func viewDidLoad() {}

l8r
Sean

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t

been discussed already, so I’m sorry if that is the case.

I would like to see the ability to just add code to base methods instead

of overriding it and calling supers method. So basically an extension for
methods.

Example:

Now:
     override func viewDidLoad() {
             super.viewDidLoad()
             // Your code
     }

Suggestion:
     addinto func viewDidLoad() {
             // Your code
     }

My reasons:
1. Its very verbose about your intentions, which fits into Swift style.

The thing you actually want is not overriding but appending.

2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be

override but you still can append to it.

   This to make sure your API implementation will always be executed .

I’m thinking about a keyword like extendable to specify that you can only
add to it.

4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are

quite small and maybe not worth the effort.

···

On Wed, Nov 16, 2016 at 2:39 PM Sean Heber via swift-evolution < swift-evolution@swift.org> wrote:

On Nov 16, 2016, at 4:37 PM, Sean Heber <sean@fifthace.com> wrote:

On Nov 16, 2016, at 4:30 PM, Mustafa Sabur via swift-evolution < swift-evolution@swift.org> wrote:
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

_______________________________________________
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

--
Javier Soto


(Jay) #5

Hi Mustafa,

This is an interesting idea. The wording needs to be clear that it is not
adding/injecting any code into the super-class. I would call it something
like a cascading or chained method - there may be a better name and
probably already is, because deinit already behaves in a similar way - the
compiler enforces that you don’t call it directly and it cascades the calls
up the super-class chain skipping ones where deinit is not implemented.

I think this should be something declared in the super-class though, not
something that a sub-class would use for the convenience of omitting the
super call. That is, the super-class demands of the compiler that its
implementation is always called when this method is called on any sub-class
(and this enforcement is inherited so all implementations in each sub-class
are guaranteed to be called).

A class could declare a method to be chained (or whatever) and the compiler
would ensure that overrides definitely call the super method, or
automatically inject it if they don’t. This would give sub-classes the
flexibility to call it anywhere they like (before or after or in the middle
of their implementation) and they could also modify the parameters passed
to it. There could also be head/tail variations that enforce super is
called at the beginning or end of sub-class implementations, rather than
anywhere.

This is also similar to how the compiler enforces the init calls are made
up the class hierarchy, but with init each sub-class might have different
parameters for their initialisers. However with a method, if you introduce
different/additional parameters it is now a new method, and no longer an
override. Would it be desirable to enforce a chain in this case - when a
sub-class wants to change the signature part way down the chain such that
all its sub-classes cannot override the original method but must use a
different one instead? This seems related but probably needs a lot more
thought and a diverse set of examples to guide the design.

···

On Wed, 16 Nov 2016 at 22:30 Mustafa Sabur via swift-evolution < swift-evolution@swift.org> wrote:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t
been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead
of overriding it and calling supers method. So basically an extension for
methods.

Example:

Now:
override func viewDidLoad() {
super.viewDidLoad()
* // Your code*
}

Suggestion:
addinto func viewDidLoad() {
* // Your code*
}

My reasons:
1. Its very verbose about your intentions, which fits into Swift style.
The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be
override but you still can append to it.
    This to make sure your API implementation will always be executed .
I’m thinking about a keyword like extendable to specify that you can only
add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are
quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Adrian Zubarev) #6

At first glance I though about this:

// Module A
open class X {
     
    open func b() {}
}

// Module B

class Y : X {
    addinto func b() {
        explodeExploit()
    }
}

class Z : X {}

Z().b() // does this also call my `explodeExploit` :smiley: ?
Are you speaking of code injection of a sugar like syntax like override(before/after) like Sean suggested?

···

--
Adrian Zubarev
Sent with Airmail

Am 16. November 2016 um 23:30:35, Mustafa Sabur via swift-evolution (swift-evolution@swift.org) schrieb:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
override func viewDidLoad() {
super.viewDidLoad()
// Your code
}

Suggestion:
addinto func viewDidLoad() {
// Your code
}

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Tino) #7

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name :wink: has been requested several times, but never got the momentum it deserves.
Considering the current confusion (especially in UIKit), it would be really nice to have some help from the compiler, and I wonder how composition and protocols would be helpful here at all.

I guess the problem is that there are to many options for this feature without an obvious favorite: Not only for the keywords, but also for the exact semantic.

Additionally, there are imho already to many access levels (private, fileprivate, internal, public, extendable?, open), so I hope we'll someday find a solution that is powerful enough to replace the special willSet/didSet treatment for properties as well.

So unless somebody has a real flash of genius, I guess it's better to delay discussion until there is a chance for new proposals to be accepted.

Tino


(Haravikk) #8

I like the basic idea, and I especially like the clarification via override at the call site, but I wanted to add the design that I preferred from the last discussion.

Basically the idea was that the parent method would have a @super() attribute with of the following attributes available to use within it:

before: super must be called before all other statements in an overriding method's body.
required: the super call is required. If neither before or after is specified it may be placed anywhere in the method's body, but must occur in all paths. This is the default if a method has a @super attribute.
optional: the super call is not required.
after: super must be called after all other statements in an overriding method's body.
error: failing to call the super method either at all or in the correct location is an error. This is the default.
warning: failing to call the super method either at all or in the correct location is a warning that a developer may choose to ignore.

So a method with @super is equivalent to @super(optional), while a method with a plain @super attribute is equivalent to @super(required, error)

I really like the idea of using override(before) at the call-site as a shorthand for having the super call as the first statement behind the scenes, and likewise for final(after).

However, with regards to a plain override, I think it should still be permitted, but the compiler will check for the presence of the super call, and that it meets the criteria specified (if any). One further caveat is that non-mutating statements (or pure functions?) should be permitted somehow, alone with simple statements, as this allows variables to be prepared, log-entries created etc. without breaking the super requirement. So for example you could do:

  class Foo { @super(before) func someMethod(foo:T) {} }
  class Bar extends Foo {
    override func someMethod(foo:T) {
      var foo = foo
      print(foo)
      mutateFooViaInout(foo) // This is a non-mutating or pure function that changes its input via inout
      super.someMethod(foo) // This is still the start as far as @super(before) is concerned
    }
  }

Part of the problem with this is that it's difficult to add the flexibility required for classes, since they don't have the concept of mutating/non-mutating; so this means we'd have to wait for that to be added and/or detection of pure functions (unless it's easy to detect already, I don't know), otherwise the @super(before) and @super(after) conditions may be too restrictive, and have to be delayed till later.

The main remaining argument was whether it is possible for the API designer to get the before/after requirement right, but then this is why I suggest the ability to make it a warning rather than an error (it could even be the default if people prefer). But I think in general API designers shouldn't add a @super attribute unless they know with certainty what they need from their design; for example if properties aren't properly instantiated/loaded unless the super method is called first, then that's a good reason to user @super(before), if there are a bunch of private properties that must be kept up-to-date then @super(required) and so-on.

Otherwise if the API designer specifies nothing, we still get a nice addition to override at the call-site to remove a little boiler-plate and keep our sub-class methods clean.

···

On 16 Nov 2016, at 22:37, Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:

That could be kind of neat - perhaps a syntax more like this so that there isn’t another bare keyword:

override(after) func viewDidLoad() {
}

and:

override(before) func viewDidLoad() {
}

Which would allow you to specify where your code happens - either before or after the superclass method, essentially. Leaving out before/after would still behave as expected and you’d have to call super yourself (or not):

override func viewDidLoad() {
// stuff
super.viewDidLoad()
// more stuff
}

A potentially neat thing about this is that you could possibly then impose restrictions on subclasses like so:

final(before) func viewDidLoad() {}

Which could mean that the “before” slot is “final” - therefore you cannot do either of these:

override func viewDidLoad() {}
override(before) func viewDidLoad() {}


(ark dan) #9

+1; if existed, i would use this feature instead of 'override' 90% of the time.

It also allows the superclass to define where to call 'super.method()' - at top or bottom of the method; although im not sure whether or not that will complicate method body of superclass with additional syntax.

···

On Nov 17, 2016, at 12:30 AM, Mustafa Sabur via swift-evolution <swift-evolution@swift.org> wrote:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
  override func viewDidLoad() {
    super.viewDidLoad()
    // Your code
  }

Suggestion:
  addinto func viewDidLoad() {
    // Your code
  }

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
    This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Mustafa Sabur) #10

Mustafa Sabur

Yes I was talking about the override(before/after) like Sean. I don’t think it would make sense to actually extend some method, since the caller might not know that it happend.
I can see some problems now and im going to try to find the old discussions. Thank you.

Mustafa Sabur

···

On 16 Nov 2016, at 23:42, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

At first glance I though about this:

// Module A
open class X {
     
    open func b() {}
}

// Module B

class Y : X {
    addinto func b() {
        explodeExploit()
    }
}

class Z : X {}

Z().b() // does this also call my `explodeExploit` :smiley: ?
Are you speaking of code injection of a sugar like syntax like override(before/after) like Sean suggested?

--
Adrian Zubarev
Sent with Airmail

Am 16. November 2016 um 23:30:35, Mustafa Sabur via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

Hallo,

I have a very simple suggestion. And I’m not very sure then it haven’t been discussed already, so I’m sorry if that is the case.
I would like to see the ability to just add code to base methods instead of overriding it and calling supers method. So basically an extension for methods.

Example:

Now:
override func viewDidLoad() {
super.viewDidLoad()
// Your code
}

Suggestion:
addinto func viewDidLoad() {
// Your code
}

My reasons:
1. Its very verbose about your intentions, which fits into Swift style. The thing you actually want is not overriding but appending.
2. You cannot make the mistake of forgetting to call the supers method.
3. It open ways to introducing ‘semi-final’ methods, which cannot be override but you still can append to it.
    This to make sure your API implementation will always be executed . I’m thinking about a keyword like extendable to specify that you can only add to it.
4. Less code.

I can’t think of any cons... Thought I can imagine that the benefits are quite small and maybe not worth the effort.
I would like to read some thoughts about this. Thank you!

Kind regards,
Mustafa Sabur

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


(Christopher Kornher) #11

If memory serves: the CLOS Metaobject Protocol had features like this. This might be good read if you are considering writing a proposal for this. (Dylan Lives! :slight_smile: )

https://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Protocol

As I remember, these sorts of features did have scalability issues.

···

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

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name :wink: has been requested several times, but never got the momentum it deserves.
Considering the current confusion (especially in UIKit), it would be really nice to have some help from the compiler, and I wonder how composition and protocols would be helpful here at all.

I guess the problem is that there are to many options for this feature without an obvious favorite: Not only for the keywords, but also for the exact semantic.

Additionally, there are imho already to many access levels (private, fileprivate, internal, public, extendable?, open), so I hope we'll someday find a solution that is powerful enough to replace the special willSet/didSet treatment for properties as well.

So unless somebody has a real flash of genius, I guess it's better to delay discussion until there is a chance for new proposals to be accepted.

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


(Tino) #12

I still thing that the naming is one of the hardest parts:
Imho "@super" just feels wrong — the word has already a meaning, and it should only be used when referring to the parent class (here, it is a restriction/hint for subclasses).
The best I can think of would be @extend (because it is about extension of the marked method)

I definitely support the idea in general, so I've something to add:
— There are already cases where super shouldn't be called (never?)
— Imho before and after only make sense if the call to super is generated automatically when it is omitted: The restriction on the order afaics offers very little (if any) additional safety, and it isn't clear how defer would interact with before.

Some questions that should imho be addressed in a formal proposal:
What about parameters and return values? Should it be possible to change those? I think so, but that would make the feature more dangerous than pure monitoring. If it's forbidden to change anything, we loose flexibility, and if it's configurable, complexity is raised.

- Tino


(Mustafa Sabur) #13

Hi all,

The most important part is that it should be easy to understand even for beginning developers. Imo the moment someone have to look it up in the docs to understand it, is the moment it has failed to serve its purpose.
I just don't like the fact that you have to use the override keyword while that's not your intention and you can forget to call super. And that it's not guaranteed that you code will run since its not final.

If you chose to solve it with optional protocols functions then you need lots of more code and there is no keyword for protocol funcs, so it's not very obvious what you are doing.

I think the before/after issue should be solved at the API part by calling it at the right moment and when you add code in a subclass it should be always after it's supers part. You should also be Albert to introduce new parameters and use the onces passed in it's super.

Mustafa Sabur

···

On 19 Nov 2016, at 16:05, Haravikk <swift-evolution@haravikk.me> wrote:

On 16 Nov 2016, at 22:37, Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:

That could be kind of neat - perhaps a syntax more like this so that there isn’t another bare keyword:

override(after) func viewDidLoad() {
}

and:

override(before) func viewDidLoad() {
}

Which would allow you to specify where your code happens - either before or after the superclass method, essentially. Leaving out before/after would still behave as expected and you’d have to call super yourself (or not):

override func viewDidLoad() {
// stuff
super.viewDidLoad()
// more stuff
}

A potentially neat thing about this is that you could possibly then impose restrictions on subclasses like so:

final(before) func viewDidLoad() {}

Which could mean that the “before” slot is “final” - therefore you cannot do either of these:

override func viewDidLoad() {}
override(before) func viewDidLoad() {}

I like the basic idea, and I especially like the clarification via override at the call site, but I wanted to add the design that I preferred from the last discussion.

Basically the idea was that the parent method would have a @super() attribute with of the following attributes available to use within it:

before: super must be called before all other statements in an overriding method's body.
required: the super call is required. If neither before or after is specified it may be placed anywhere in the method's body, but must occur in all paths. This is the default if a method has a @super attribute.
optional: the super call is not required.
after: super must be called after all other statements in an overriding method's body.
error: failing to call the super method either at all or in the correct location is an error. This is the default.
warning: failing to call the super method either at all or in the correct location is a warning that a developer may choose to ignore.

So a method with @super is equivalent to @super(optional), while a method with a plain @super attribute is equivalent to @super(required, error)

I really like the idea of using override(before) at the call-site as a shorthand for having the super call as the first statement behind the scenes, and likewise for final(after).

However, with regards to a plain override, I think it should still be permitted, but the compiler will check for the presence of the super call, and that it meets the criteria specified (if any). One further caveat is that non-mutating statements (or pure functions?) should be permitted somehow, alone with simple statements, as this allows variables to be prepared, log-entries created etc. without breaking the super requirement. So for example you could do:

  class Foo { @super(before) func someMethod(foo:T) {} }
  class Bar extends Foo {
    override func someMethod(foo:T) {
      var foo = foo
      print(foo)
      mutateFooViaInout(foo) // This is a non-mutating or pure function that changes its input via inout
      super.someMethod(foo) // This is still the start as far as @super(before) is concerned
    }
  }

Part of the problem with this is that it's difficult to add the flexibility required for classes, since they don't have the concept of mutating/non-mutating; so this means we'd have to wait for that to be added and/or detection of pure functions (unless it's easy to detect already, I don't know), otherwise the @super(before) and @super(after) conditions may be too restrictive, and have to be delayed till later.

The main remaining argument was whether it is possible for the API designer to get the before/after requirement right, but then this is why I suggest the ability to make it a warning rather than an error (it could even be the default if people prefer). But I think in general API designers shouldn't add a @super attribute unless they know with certainty what they need from their design; for example if properties aren't properly instantiated/loaded unless the super method is called first, then that's a good reason to user @super(before), if there are a bunch of private properties that must be kept up-to-date then @super(required) and so-on.

Otherwise if the API designer specifies nothing, we still get a nice addition to override at the call-site to remove a little boiler-plate and keep our sub-class methods clean.


(Michael Ilseman) #14

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name :wink: has been requested several times, but never got the momentum it deserves.
Considering the current confusion (especially in UIKit), it would be really nice to have some help from the compiler, and I wonder how composition and protocols would be helpful here at all.

As an intermediary measure, this seems like an interesting QoI improvement for the compiler: warn when super.foo() is not called in the overridden method. This is probably best done through a Clang-side attribute to begin with (as UIKit and others are the biggest bang for the buck for this), and of course some kind of NS_* convenience macro could be added.

What are your thoughts on this?

Just to throw out a strawman:

// Warn if override doesn’t begin with “super.foo()”
__attribute(swift_requires_super_call_at_begin)

// Warn if override doesn’t end with “super.foo()”
__attribute(swift_requires_super_call_at_end)

···

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

I guess the problem is that there are to many options for this feature without an obvious favorite: Not only for the keywords, but also for the exact semantic.

Additionally, there are imho already to many access levels (private, fileprivate, internal, public, extendable?, open), so I hope we'll someday find a solution that is powerful enough to replace the special willSet/didSet treatment for properties as well.

So unless somebody has a real flash of genius, I guess it's better to delay discussion until there is a chance for new proposals to be accepted.

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


(Haravikk) #15

I still thing that the naming is one of the hardest parts:
Imho "@super" just feels wrong — the word has already a meaning, and it should only be used when referring to the parent class (here, it is a restriction/hint for subclasses).
The best I can think of would be @extend (because it is about extension of the marked method)

I like it because it aligns with what you're actually restricting, but obviously all naming is up for debate.
The use of final for this purpose is okay, but it doesn't really fit the required and optional attributes which I think are also useful to have now or in future.
@extend is a good possibility though.

I definitely support the idea in general, so I've something to add:
— There are already cases where super shouldn't be called (never?)

I can't remember if I had that case in the previous discussion or not, but there's certainly an argument for an additional "never" attribute to prevent the use of super at all!

— Imho before and after only make sense if the call to super is generated automatically when it is omitted: The restriction on the order afaics offers very little (if any) additional safety, and it isn't clear how defer would interact with before.

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

I forgot all about defer though! They're a bit trickier in the case of @extend(after) or whatever, since deferred statements cannot be executed before the super call. They should be fine in the @extend(before) case though as they can only run after the super method or when it's in the process of throwing without a try. So I suppose it means they will have to produce an error/warning in a regular override if the @extend(after) restriction is present, but should be fine in the override(after) case (implicit super method call after body) assuming the deferred code would execute before the super call in that case; since it will resembled its own scope this should be fine I think? Otherwise you need to make sure you perform the defer within a more limited scope in order to control when it eventually executes.

Some questions that should imho be addressed in a formal proposal:
What about parameters and return values? Should it be possible to change those? I think so, but that would make the feature more dangerous than pure monitoring. If it's forbidden to change anything, we loose flexibility, and if it's configurable, complexity is raised.

This is why I think we still need to allow the general override case so we can put the super method wherever we like with an error/warning if breaks any requirement, as developers can add safe code before or after to do any additional processing of parameters/return values. The override(before) and override(after) would just be a shorthand for when you want

The most important part is that it should be easy to understand even for beginning developers. Imo the moment someone have to look it up in the docs to understand it, is the moment it has failed to serve its purpose.

I don't think that Sean's override(before/after) should be any more difficult than addinto; in fact it's arguable that addinto doesn't contain enough information as is unclear what's going on as it looks like an entirely new concept, whereas using the override keyword keeps it clear.

I just don't like the fact that you have to use the override keyword while that's not your intention and you can forget to call super. And that it's not guaranteed that you code will run since its not final.

Whether or not it's your intention, overriding is what you're doing; I think it's important to keep that clear. I'm not sure what you mean about finality?

···

On 19 Nov 2016, at 17:08, Tino Heth <2th@gmx.de> wrote:
On 19 Nov 2016, at 17:29, Mustafa Sabur <mustafa.sabur@icloud.com> wrote:


(Tino) #16

What are your thoughts on this?

Just to throw out a strawman:

// Warn if override doesn’t begin with “super.foo()”
__attribute(swift_requires_super_call_at_begin)

// Warn if override doesn’t end with “super.foo()”
__attribute(swift_requires_super_call_at_end)

I myself would already be happy if Swift had an equivalent to NS_REQUIRES_SUPER (preferably with a different name ;-).
The ability to indicate that super shouldn't be called when overriding would be nice as well — both situations happen in Cocoa, and it isn't enforced, but only documented.

I don't have any examples where the position of the call to super matters, and my personal opinion is that this feature wouldn't pay off:
Of course, there are situations where order is important — but as with willSet/didSet, it might only be important for the overriding class, not for super.

- Tino


(Dave Abrahams) #17

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

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

understating-the-case-ly y'rs,

···

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

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

An equivalent of "NS_REQUIRES_SUPER" (hopefully with a better name :wink: has been requested several

times, but never got the momentum it deserves.

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

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

--
-Dave


(Tino) #18

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

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

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

It is different when the call to super would be inserted automatically:
I don't think that one of the choices is superior, so it should be up to the author to decide what is preferred.

I'm not sure if it is a good idea to generate calls to super at all — but it would be similar to willSet/didSet.

- Tino


(Kevin Nattinger) #19

I agree. An NS_REQUIRES_SUPER equivalent was on my list of things to propose during stage 2, and I don't see a reason to enforce order.

···

On Nov 25, 2016, at 04:42, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

What are your thoughts on this?

Just to throw out a strawman:

// Warn if override doesn’t begin with “super.foo()”
__attribute(swift_requires_super_call_at_begin)

// Warn if override doesn’t end with “super.foo()”
__attribute(swift_requires_super_call_at_end)

I myself would already be happy if Swift had an equivalent to NS_REQUIRES_SUPER (preferably with a different name ;-).
The ability to indicate that super shouldn't be called when overriding would be nice as well ― both situations happen in Cocoa, and it isn't enforced, but only documented.

I don't have any examples where the position of the call to super matters, and my personal opinion is that this feature wouldn't pay off:
Of course, there are situations where order is important ― but as with willSet/didSet, it might only be important for the overriding class, not for super.

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


(Aron Lindberg) #20

I have also been considering something like this for stage 2, but since we are discussing it now this is what I think would be most feasible:

1) Unless you know exactly what a subclass should do, you can not make assumptions about when a subclass should call its super implementation. This is truer the more general the class is. Take the method setFrame on NSView as an example; We might want to save some state before calling super, we might want to tweak the input parameters before sending them on to super, and we properly want to perform some custom view logic after calling super. NSView have no way of knowing when you should invoke super in a subclass.

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

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

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

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

Please let me know what you think, but I think a formal proposal should wait to stage 2.

···

On 25 Nov 2016, at 17.36, Kevin Nattinger via swift-evolution <swift-evolution@swift.org> wrote:

I agree. An NS_REQUIRES_SUPER equivalent was on my list of things to propose during stage 2, and I don't see a reason to enforce order.

On Nov 25, 2016, at 04:42, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

What are your thoughts on this?

Just to throw out a strawman:

// Warn if override doesn’t begin with “super.foo()”
__attribute(swift_requires_super_call_at_begin)

// Warn if override doesn’t end with “super.foo()”
__attribute(swift_requires_super_call_at_end)

I myself would already be happy if Swift had an equivalent to NS_REQUIRES_SUPER (preferably with a different name ;-).
The ability to indicate that super shouldn't be called when overriding would be nice as well — both situations happen in Cocoa, and it isn't enforced, but only documented.

I don't have any examples where the position of the call to super matters, and my personal opinion is that this feature wouldn't pay off:
Of course, there are situations where order is important — but as with willSet/didSet, it might only be important for the overriding class, not for super.

- Tino
_______________________________________________
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