Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall


(Florian Liefers) #1

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
   func viewDidLoad() {
      // does something
   }
}

class Button: View {
  override func viewDidLoad() {
      super.viewDidLoad() // <— this might be forgotten
      // do something other
   }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
  extend func viewDidLoad() {
      super.viewDidLoad()
      // do something
   }

  extend func viewDidAppear() {
      // do something
   } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
   func volume() -> Double {
      return 0;
   }
}

class Cube: Geometry {
   var length: Double = 0.0
   replace func volume() -> Double {
      let v = length * length * length
      return v
   }
}

Cheers,
Florian


(Haravikk) #2

This is an interesting idea, and fits well with the theme of preventing mistakes in Swift, but I think that the proposed solution isn’t flexible enough, as there are cases for inheritance patterns where extending doesn’t actually make sense, so having to specify an exception every time could quickly become annoying.

I think the better solution is to instead allow super-classes to specify whether or not their method must be called when overridden/extended. For example:

  class View {
    @super(required) func viewDidLoad() { … }
  }

  class Button : View {
    override func viewDidLoad() { … }
  }

  class Widget : View {
    override func viewDidLoad() {
      super.viewDidLoad()
      …
    }
  }

In this extension of your example Button will cause an error because it overrides viewDidLoad() but fails to call the parent’s method as required by the @super attribute. However, Widget compiles successfully because it follows the requirement.

So the options for @super would be:

required: child-class must call parent implementation of this method.
optional: default behaviour, child can choose whether to call the parent’s method.
denied: child may not call parent’s method (useful if it makes assumptions that a child-class may not follow), but can still extend/override.

I think this would be a more flexible solution to the problem, and put the decision in the hands of those writing classes designed for inheritance. I’m not 100% sure of whether to rename override to extend, I like extend better personally, but it probably doesn’t matter overall.

···

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution <swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

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


(Alexey Demedetskiy) #3

Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
    // super.viewDidLoad() <— no need to call super at first line.
    // child code
}

override(before) func tearDown() {
    // clean code
    // super… inserted by compiler
}

override(instead) func loadView() {
    // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
}

override func refillHealthBar() {
   // absent call to super will cause an error with fix-up to add (instead) modifier
}

I am not sure about exposing this in a public interface and limit child override options.

But in general - what is your thoughts about this approach to problem that you mention?

···

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
func viewDidLoad() {
// does something
}
}

class Button: View {
override func viewDidLoad() {
super.viewDidLoad() //<— this might be forgotten
// do something other
}
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
super.viewDidLoad()
// do something
}

extend func viewDidAppear() {
// do something
} //<— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
func volume() ->Double {
return 0;
}
}

class Cube: Geometry {
var length: Double = 0.0
replace func volume() ->Double {
let v = length * length * length
return v
}
}

Cheers,
Florian


(Ricardo Parada) #4

Hi Florian,

I have always taken care of this problem in other languages without recurring to specialized language features. For example:

class Foo {
    func _someMethod() {
  // Do something important
  …

  // Now give subclassers a chance to do something
  someMethod()
    }

    func someMethod() {
  // Default does nothing
    }
}

This way you are in control when someone else overrides someMethod since _someMethod() does the important stuff first and then calls someMethod() to allow those extending the class to do something.

Also, I can modify _someMethod() and move the “Do something important” part to be after the call to someMethod().

···

On Feb 15, 2016, at 3:57 PM, Florian Liefers via swift-evolution <swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

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


(Shawn Erickson) #5

+1 for what you outlined Alexey. I think maintaining the use of override as
the keyword is the most understandable in the context and also is
terminology usually used in various object languages. I like adding the
optional qualifiers to allow (1) better diagnostics by the compiler, (2)
clearer code, and (3) the opportunity for compiler generating the need
coded (in a few of the situations).

Can something like this be used in the super classes interface definition
to clarify expectations of a subclass?

···

On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution < swift-evolution@swift.org> wrote:

Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do
nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc.
All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
    // super.viewDidLoad() <— no need to call super at first line.
    // child code
}

override(before) func tearDown() {
    // clean code
    // super… inserted by compiler
}

override(instead) func loadView() {
    // super.loadView() <— marked as an error with appropriate fix-up to
remove instead modifier
}

override func refillHealthBar() {
   // absent call to super will cause an error with fix-up to add
(instead) modifier
}

I am not sure about exposing this in a public interface and limit child
override options.

But in general - what is your thoughts about this approach to problem that
you mention?

> Hi!
>
> I would like to suggest to replace the override keyword for functions by
something like extend and replace or to add an annotation like
@SuppressSuperCall (don’t know a good name for it).
> The reason for this is, that it might happen, that one forgets to call
the super’s implementation in an overridden function or if one reads the
code it might not be obvious why the super’s implementation is not called:
>
> class View {
> func viewDidLoad() {
> // does something
> }
> }
>
> class Button: View {
> override func viewDidLoad() {
> super.viewDidLoad() //<— this might be forgotten
> // do something other
> }
> }
>
> The compiler will accept if one overrides a superclass’s function but
does not call the superclass’s implementation which is often ok. The
developer should clearly state that he doesn’t want to call the
superclass’s implementation, otherwise the compiler should throw an error.
>
> // Example for extending a function
> class Button: View {
> extend func viewDidLoad() {
> super.viewDidLoad()
> // do something
> }
>
> extend func viewDidAppear() {
> // do something
> } //<— the compiler should throw an error here.
> }
>
> // Example for replacing a function
> class Geometry {
> func volume() ->Double {
> return 0;
> }
> }
>
> class Cube: Geometry {
> var length: Double = 0.0
> replace func volume() ->Double {
> let v = length * length * length
> return v
> }
> }
>
> Cheers,
> Florian
>
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vanderlei Martinelli) #6

+1 to @super :slight_smile:

···

On Mon, Feb 15, 2016 at 8:52 PM, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

This is an interesting idea, and fits well with the theme of preventing
mistakes in Swift, but I think that the proposed solution isn’t flexible
enough, as there are cases for inheritance patterns where extending doesn’t
actually make sense, so having to specify an exception every time could
quickly become annoying.

I think the better solution is to instead allow super-classes to specify
whether or not their method must be called when overridden/extended. For
example:

class View {
@super(required) func viewDidLoad() { … }
}

class Button : View {
override func viewDidLoad() { … }
}

class Widget : View {
override func viewDidLoad() {
super.viewDidLoad()

}
}

In this extension of your example Button will cause an error because it
overrides viewDidLoad() but fails to call the parent’s method as required
by the @super attribute. However, Widget compiles successfully because it
follows the requirement.

So the options for @super would be:

   - *required: *child-class must call parent implementation of this
   method.
   - *optional:* default behaviour, child can choose whether to call the
   parent’s method.
   - *denied:* child may not call parent’s method (useful if it makes
   assumptions that a child-class may not follow), but can still
   extend/override.

I think this would be a more flexible solution to the problem, and put the
decision in the hands of those writing classes designed for inheritance.
I’m not 100% sure of whether to rename override to extend, I like extend
better personally, but it probably doesn’t matter overall.

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution < > swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by
something like extend and replace or to add an annotation like
@SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the
super’s implementation in an overridden function or if one reads the code
it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does
not call the superclass’s implementation which is often ok. The developer
should clearly state that he doesn’t want to call the superclass’s
implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

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

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


(Haravikk) #7

Oh, it looks like Alexey beat me to a similar solution, but split the thread (at least in Mail.app):

···

On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
   // super.viewDidLoad() <— no need to call super at first line.
   // child code
}

override(before) func tearDown() {
   // clean code
   // super… inserted by compiler
}

override(instead) func loadView() {
   // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
}

override func refillHealthBar() {
  // absent call to super will cause an error with fix-up to add (instead) modifier
}

I am not sure about exposing this in a public interface and limit child override options.

But in general - what is your thoughts about this approach to problem that you mention?

On 15 Feb 2016, at 22:52, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

This is an interesting idea, and fits well with the theme of preventing mistakes in Swift, but I think that the proposed solution isn’t flexible enough, as there are cases for inheritance patterns where extending doesn’t actually make sense, so having to specify an exception every time could quickly become annoying.

I think the better solution is to instead allow super-classes to specify whether or not their method must be called when overridden/extended. For example:

  class View {
    @super(required) func viewDidLoad() { … }
  }

  class Button : View {
    override func viewDidLoad() { … }
  }

  class Widget : View {
    override func viewDidLoad() {
      super.viewDidLoad()
      …
    }
  }

In this extension of your example Button will cause an error because it overrides viewDidLoad() but fails to call the parent’s method as required by the @super attribute. However, Widget compiles successfully because it follows the requirement.

So the options for @super would be:

required: child-class must call parent implementation of this method.
optional: default behaviour, child can choose whether to call the parent’s method.
denied: child may not call parent’s method (useful if it makes assumptions that a child-class may not follow), but can still extend/override.

I think this would be a more flexible solution to the problem, and put the decision in the hands of those writing classes designed for inheritance. I’m not 100% sure of whether to rename override to extend, I like extend better personally, but it probably doesn’t matter overall.

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

Cheers,
Florian
_______________________________________________
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


(Goffredo Marocchi) #8

I like your idea of @super() a lot :)!

···

Sent from my iPhone

On 15 Feb 2016, at 22:52, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

This is an interesting idea, and fits well with the theme of preventing mistakes in Swift, but I think that the proposed solution isn’t flexible enough, as there are cases for inheritance patterns where extending doesn’t actually make sense, so having to specify an exception every time could quickly become annoying.

I think the better solution is to instead allow super-classes to specify whether or not their method must be called when overridden/extended. For example:

  class View {
    @super(required) func viewDidLoad() { … }
  }

  class Button : View {
    override func viewDidLoad() { … }
  }

  class Widget : View {
    override func viewDidLoad() {
      super.viewDidLoad()
      …
    }
  }

In this extension of your example Button will cause an error because it overrides viewDidLoad() but fails to call the parent’s method as required by the @super attribute. However, Widget compiles successfully because it follows the requirement.

So the options for @super would be:

required: child-class must call parent implementation of this method.
optional: default behaviour, child can choose whether to call the parent’s method.
denied: child may not call parent’s method (useful if it makes assumptions that a child-class may not follow), but can still extend/override.

I think this would be a more flexible solution to the problem, and put the decision in the hands of those writing classes designed for inheritance. I’m not 100% sure of whether to rename override to extend, I like extend better personally, but it probably doesn’t matter overall.

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution <swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

Cheers,
Florian
_______________________________________________
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


(Jean-Daniel) #9

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

···

Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org> a écrit :

Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
   // super.viewDidLoad() <— no need to call super at first line.
   // child code
}

override(before) func tearDown() {
   // clean code
   // super… inserted by compiler
}

override(instead) func loadView() {
   // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
}

override func refillHealthBar() {
  // absent call to super will cause an error with fix-up to add (instead) modifier
}

I am not sure about exposing this in a public interface and limit child override options.

But in general - what is your thoughts about this approach to problem that you mention?

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
func viewDidLoad() {
// does something
}
}

class Button: View {
override func viewDidLoad() {
super.viewDidLoad() //<— this might be forgotten
// do something other
}
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
super.viewDidLoad()
// do something
}

extend func viewDidAppear() {
// do something
} //<— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
func volume() ->Double {
return 0;
}
}

class Cube: Geometry {
var length: Double = 0.0
replace func volume() ->Double {
let v = length * length * length
return v
}
}

Cheers,
Florian

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


(Florian Liefers) #10

Hi Recardo,

this will only work for calls inside the superclass, but for calls from outside the class you have no control. If one calls Foo().someMethod() directly, _someMethod is not executed.

— Florian

···

Am 16.02.2016 um 23:43 schrieb Ricardo Parada <rparada@mac.com>:

Hi Florian,

I have always taken care of this problem in other languages without recurring to specialized language features. For example:

class Foo {
    func _someMethod() {
  // Do something important
  …

  // Now give subclassers a chance to do something
  someMethod()
    }

    func someMethod() {
  // Default does nothing
    }
}

This way you are in control when someone else overrides someMethod since _someMethod() does the important stuff first and then calls someMethod() to allow those extending the class to do something.

Also, I can modify _someMethod() and move the “Do something important” part to be after the call to someMethod().

On Feb 15, 2016, at 3:57 PM, Florian Liefers via swift-evolution <swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

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


(Kyle Sherman) #11

I was working on a proposal just like this, so I submitted it for discussion today. Check it out. It’s called Enforcing Calling Super.

-Kyle

···

This is an interesting idea, and fits well with the theme of preventing mistakes in Swift, but I think that the proposed solution isn’t flexible enough, as there are cases for inheritance patterns where extending doesn’t actually make sense, so having to specify an exception every time could quickly become annoying.

I think the better solution is to instead allow super-classes to specify whether or not their method must be called when overridden/extended. For example:

class View {
@super(required) func viewDidLoad() { … }
}

class Button : View {
override func viewDidLoad() { … }
}

class Widget : View {
override func viewDidLoad() {
super.viewDidLoad()

}
}

In this extension of your example Button will cause an error because it overrides viewDidLoad() but fails to call the parent’s method as required by the @super attribute. However, Widget compiles successfully because it follows the requirement.

So the options for @super would be:

required: child-class must call parent implementation of this method.
optional: default behaviour, child can choose whether to call the parent’s method.
denied: child may not call parent’s method (useful if it makes assumptions that a child-class may not follow), but can still extend/override.

I think this would be a more flexible solution to the problem, and put the decision in the hands of those writing classes designed for inheritance. I’m not 100% sure of whether to rename override to extend, I like extend better personally, but it probably doesn’t matter overall.

> On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution<swift-evolution at swift.org>wrote:
>
> Hi!
>
> I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
> The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:
>
> class View {
> func viewDidLoad() {
> // does something
> }
> }
>
> class Button: View {
> override func viewDidLoad() {
> super.viewDidLoad() //<— this might be forgotten
> // do something other
> }
> }
>
> The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.
>
> // Example for extending a function
> class Button: View {
> extend func viewDidLoad() {
> super.viewDidLoad()
> // do something
> }
>
> extend func viewDidAppear() {
> // do something
> } //<— the compiler should throw an error here.
> }
>
> // Example for replacing a function
> class Geometry {
> func volume() ->Double {
> return 0;
> }
> }
>
> class Cube: Geometry {
> var length: Double = 0.0
> replace func volume() ->Double {
> let v = length * length * length
> return v
> }
> }
>
> Cheers,
> Florian
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #12

Is that the correct way around? I would have thought that _someMethod() would be the no-op that sub-classes can override? In languages where I’ve done this I would usually use doSomeMethod() but whatever.

While it’s a valid design pattern, it doesn’t really work in Swift due to the lack of a protected (sub-classes only) visibility type.
Even if we did have protected visibility, the other problem is that you still have a single function to override, so what happens when you want a second level of extension? Either the child method has to hope that further sub-classes don’t mess it up, or they have to mark it as final and declare their own new child method for each level below them. Aside from being a fun thing to find names for, it could get messy very quickly, it’d be much cleaner supported by a language feature, and could actually be more explicitly defined as well.

···

On 16 Feb 2016, at 22:43, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:

Hi Florian,

I have always taken care of this problem in other languages without recurring to specialized language features. For example:

class Foo {
    func _someMethod() {
  // Do something important
  …

  // Now give subclassers a chance to do something
  someMethod()
    }

    func someMethod() {
  // Default does nothing
    }
}

This way you are in control when someone else overrides someMethod since _someMethod() does the important stuff first and then calls someMethod() to allow those extending the class to do something.

Also, I can modify _someMethod() and move the “Do something important” part to be after the call to someMethod().


(Shawn Erickson) #13

Any clarity on when to use @ to prefix a keyword?

···

On Mon, Feb 15, 2016 at 4:53 PM Vanderlei Martinelli via swift-evolution < swift-evolution@swift.org> wrote:

+1 to @super :slight_smile:

On Mon, Feb 15, 2016 at 8:52 PM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

This is an interesting idea, and fits well with the theme of preventing
mistakes in Swift, but I think that the proposed solution isn’t flexible
enough, as there are cases for inheritance patterns where extending doesn’t
actually make sense, so having to specify an exception every time could
quickly become annoying.

I think the better solution is to instead allow super-classes to specify
whether or not their method must be called when overridden/extended. For
example:

class View {
@super(required) func viewDidLoad() { … }
}

class Button : View {
override func viewDidLoad() { … }
}

class Widget : View {
override func viewDidLoad() {
super.viewDidLoad()

}
}

In this extension of your example Button will cause an error because it
overrides viewDidLoad() but fails to call the parent’s method as required
by the @super attribute. However, Widget compiles successfully because it
follows the requirement.

So the options for @super would be:

   - *required: *child-class must call parent implementation of this
   method.
   - *optional:* default behaviour, child can choose whether to call the
   parent’s method.
   - *denied:* child may not call parent’s method (useful if it makes
   assumptions that a child-class may not follow), but can still
   extend/override.

I think this would be a more flexible solution to the problem, and put
the decision in the hands of those writing classes designed for
inheritance. I’m not 100% sure of whether to rename override to extend, I
like extend better personally, but it probably doesn’t matter overall.

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution < >> swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by
something like extend and replace or to add an annotation like
@SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call
the super’s implementation in an overridden function or if one reads the
code it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but
does not call the superclass’s implementation which is often ok. The
developer should clearly state that he doesn’t want to call the
superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

Cheers,
Florian
_______________________________________________
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


(Ross O'Brien) #14

Jean-Daniel: can you clarify which aspect you're disagreeing with?

For example: should standard library types prefer the 'override' form which
enforces calling super but doesn't enforce when it is called?
Perhaps 'override(before)' should be an indication that, if the overriding
method doesn't explicitly declare the super call, then it should be called
implicitly at the start of the function?

···

On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution < swift-evolution@swift.org> wrote:

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance,
there is absolutely no need to enforce it and it may result in problem when
some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the
super.viewDidLoad().

> Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution < > swift-evolution@swift.org> a écrit :
>
> Hi
>
> I would like to suggest you to extend your proposal.
>
> In my practice, overriding super functions can have several semantics.
> 1) Replace - simple case for abstract classes which implementation do
nothing, or throw an exceptions.
> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc.
All cases where super expect to be called before child code.
> 3) Before super - opposite to 2.
> 4) Override - no rules about order, but super call must be done.
>
> So code can look like:
>
> override(after) func viewDidLoad() {
> // super.viewDidLoad() <— no need to call super at first line.
> // child code
> }
>
> override(before) func tearDown() {
> // clean code
> // super… inserted by compiler
> }
>
> override(instead) func loadView() {
> // super.loadView() <— marked as an error with appropriate fix-up to
remove instead modifier
> }
>
> override func refillHealthBar() {
> // absent call to super will cause an error with fix-up to add
(instead) modifier
> }
>
> I am not sure about exposing this in a public interface and limit child
override options.
>
> But in general - what is your thoughts about this approach to problem
that you mention?
>
>
>> Hi!
>>
>> I would like to suggest to replace the override keyword for functions
by something like extend and replace or to add an annotation like
@SuppressSuperCall (don’t know a good name for it).
>> The reason for this is, that it might happen, that one forgets to call
the super’s implementation in an overridden function or if one reads the
code it might not be obvious why the super’s implementation is not called:
>>
>> class View {
>> func viewDidLoad() {
>> // does something
>> }
>> }
>>
>> class Button: View {
>> override func viewDidLoad() {
>> super.viewDidLoad() //<— this might be forgotten
>> // do something other
>> }
>> }
>>
>> The compiler will accept if one overrides a superclass’s function but
does not call the superclass’s implementation which is often ok. The
developer should clearly state that he doesn’t want to call the
superclass’s implementation, otherwise the compiler should throw an error.
>>
>> // Example for extending a function
>> class Button: View {
>> extend func viewDidLoad() {
>> super.viewDidLoad()
>> // do something
>> }
>>
>> extend func viewDidAppear() {
>> // do something
>> } //<— the compiler should throw an error here.
>> }
>>
>> // Example for replacing a function
>> class Geometry {
>> func volume() ->Double {
>> return 0;
>> }
>> }
>>
>> class Cube: Geometry {
>> var length: Double = 0.0
>> replace func volume() ->Double {
>> let v = length * length * length
>> return v
>> }
>> }
>>
>> Cheers,
>> Florian
>>
>>
>>
> _______________________________________________
> 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


(Howard Lovatt) #15

Building on Haravikk's suggestion:

    1. Make methods and classes final by default and mark an overridable
class with `class(option)` or `class(replace)` (see below for
`class(replace)`).
    2. A function declaration requires one of `func`, `func(final)`,
`func(replace)`, `func(option)`, `func(before)`, `func(after)`, or
`func(instead)` keywords and a function override requires one of
`override`, `override(final)`, `override(replace)`,
`override(option)`, `override(before)`, `override(after)`, or
`override(instead) - note no func keyword.
    3. A change from Haravikk's suggestion, retain the current meaning of
override (with different notation) so that `override(option)` means that
you can call super anywhere or not at all. (Equivalent to current
`override`.)
    4. Establish a hierarchy, since the override becomes part of the
method's public signature, in particular:
        4.a. `func/override(replace)` can be overridden/implemented by any
form, i.e. one of `override(replace)`, `override(replace,
option)`, `override(replace, before)`, `override(replace, after)`,
and `override(replace, instead)`. (Note the two qualifiers: what you are
going from to what you are going to.)
        4.b. `func/override(option)` can be overridden/implemented
by `override(option)`, `override(option, before)`, `override(option,
after)`, or `override(option, instead)`.
        4.c. `func/override(before)`, `func/override(after)`, and
`func/override(instead)` can only be overridden/implemented by the same
modifier.
    5. Methods in protocols and classes that do not have a body are
automatically `func/override(replace)`. (Currently protocols cannot have
bodies, but that is likely to change.) Final methods must have a body, i.e.
`func(final) method()` is an error because it is final and has no body.
    6. A class with a method without a body, which must be marked
`func/override` or `func/override(replace)`, has to be marked
`class(replace)`; it is abstract. (Note the notation `class(option)` and
`class(replace)` is consistent, a `class(option)` has at least one
optionally overridable method and no `func/override(replace)` methods,
whereas a class with at least one `func/override(replace)` method is marked
`class(replace)`.)
   7. Any of the annotations can be extended with final, e.g.
`func(optional, final)` means it is overriding a `func(optional)` but from
this point down it is final. Final methods must have a body.
   8. In a class/protocol `func` is shorthand for `func(final)` unless the
method has no body in which case it is shorthand for `func(replace)`.
   9. `override` is a shorthand for `override(A, final)` where A is the
annotation specified in the matching `func` declaration.
   10. Overriding methods in a final class do not require the extra final
annotation, e.g. in a final class `func(option)` and `func(option, final)`
are equivalent.

EG:

    class(replace) Abstract { // Point 1: class marked as replace, it is
therefore abstract and you can't call init. Point 6: it has an abstract
method therefore must be abstract itself.
        func abstract() // Point 5: declare an abstract method (it has no
body), equivalent to `func(replace)`.

        func(option) overridable() { // Point 2: declare an optionally
overridable method. Point 3: same override semantics as Swift 2.
            print("Optionally overridable with any super call OK")
        }

        func finalFunc() { // Point 1: methods are final by default. Point
8: `func` is shorthand for `func(final)` when the method has a body.
            print("Method is final")
        }
    }

    class Final: Overridable { // Point 1: class is final since it isn't
annotated.
        override abstract() { // Point 2: override keyword not func. Point
7: method is final because class is final. Point 9: `override` is
equivalent to `override(replace, final)`.
            print("Implementation of abstract method")
        }

        override overridable() { // Point 2: override keyword not func.
Point 7: method is final because class is final. Point 9: `override` is
equivalent to `override(option, final)`.
            print("Method is final because class is final")
        }
    }

    class(option) Derived: Overridable { // Point 1: class is overridable
because it is annotated option.
        override(replace, after) abstract() { // Point 4.a: implementation
of an abstract class
            print("In a derived class this will be printed after the
derived class's body has finished")
        }

        override(option, final) overridable() { // Point 7: method is final
because it is annotated final.
            print("Method is final because class is final")
        }
    }

  -- Howard.

···

On 16 February 2016 at 09:56, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

Oh, it looks like Alexey beat me to a similar solution, but split the
thread (at least in Mail.app):

On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution < > swift-evolution@swift.org> wrote:

Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do
nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc.
All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
   // super.viewDidLoad() <— no need to call super at first line.
   // child code
}

override(before) func tearDown() {
   // clean code
   // super… inserted by compiler
}

override(instead) func loadView() {
   // super.loadView() <— marked as an error with appropriate fix-up to
remove instead modifier
}

override func refillHealthBar() {
  // absent call to super will cause an error with fix-up to add (instead)
modifier
}

I am not sure about exposing this in a public interface and limit child
override options.

But in general - what is your thoughts about this approach to problem that
you mention?

On 15 Feb 2016, at 22:52, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

This is an interesting idea, and fits well with the theme of preventing
mistakes in Swift, but I think that the proposed solution isn’t flexible
enough, as there are cases for inheritance patterns where extending doesn’t
actually make sense, so having to specify an exception every time could
quickly become annoying.

I think the better solution is to instead allow super-classes to specify
whether or not their method must be called when overridden/extended. For
example:

class View {
@super(required) func viewDidLoad() { … }
}

class Button : View {
override func viewDidLoad() { … }
}

class Widget : View {
override func viewDidLoad() {
super.viewDidLoad()

}
}

In this extension of your example Button will cause an error because it
overrides viewDidLoad() but fails to call the parent’s method as required
by the @super attribute. However, Widget compiles successfully because it
follows the requirement.

So the options for @super would be:

   - *required: *child-class must call parent implementation of this
   method.
   - *optional:* default behaviour, child can choose whether to call the
   parent’s method.
   - *denied:* child may not call parent’s method (useful if it makes
   assumptions that a child-class may not follow), but can still
   extend/override.

I think this would be a more flexible solution to the problem, and put the
decision in the hands of those writing classes designed for inheritance.
I’m not 100% sure of whether to rename override to extend, I like extend
better personally, but it probably doesn’t matter overall.

On 15 Feb 2016, at 20:57, Florian Liefers via swift-evolution < > swift-evolution@swift.org> wrote:

Hi!

I would like to suggest to replace the override keyword for functions by
something like extend and replace or to add an annotation like
@SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the
super’s implementation in an overridden function or if one reads the code
it might not be obvious why the super’s implementation is not called:

class View {
  func viewDidLoad() {
     // does something
  }
}

class Button: View {
override func viewDidLoad() {
     super.viewDidLoad() // <— this might be forgotten
     // do something other
  }
}

The compiler will accept if one overrides a superclass’s function but does
not call the superclass’s implementation which is often ok. The developer
should clearly state that he doesn’t want to call the superclass’s
implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
     super.viewDidLoad()
     // do something
  }

extend func viewDidAppear() {
     // do something
  } // <— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
  func volume() -> Double {
     return 0;
  }
}

class Cube: Geometry {
  var length: Double = 0.0
  replace func volume() -> Double {
     let v = length * length * length
     return v
  }
}

Cheers,
Florian
_______________________________________________
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


(Jean-Daniel) #16

I disagree with the introduction of a method to specify if super must be call first or last. Defining that super must be call is fine, but I don’t see why the operation order should be enforced.

If the super class declares a method overridable but require that some code must be perform first, it can simply execute that code before calling the overridable method instead of putting it in the super class definition then force the subclass to call super first.

Moreover, I’m not fond of declaring that requirement in the overriding classes. That is the superclass that should define if a super implementation is required, not the children classes.

···

Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution <swift-evolution@swift.org> a écrit :

Jean-Daniel: can you clarify which aspect you're disagreeing with?

For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?

On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

> Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>
> Hi
>
> I would like to suggest you to extend your proposal.
>
> In my practice, overriding super functions can have several semantics.
> 1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
> 3) Before super - opposite to 2.
> 4) Override - no rules about order, but super call must be done.
>
> So code can look like:
>
> override(after) func viewDidLoad() {
> // super.viewDidLoad() <— no need to call super at first line.
> // child code
> }
>
> override(before) func tearDown() {
> // clean code
> // super… inserted by compiler
> }
>
> override(instead) func loadView() {
> // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
> }
>
> override func refillHealthBar() {
> // absent call to super will cause an error with fix-up to add (instead) modifier
> }
>
> I am not sure about exposing this in a public interface and limit child override options.
>
> But in general - what is your thoughts about this approach to problem that you mention?
>
>
>> Hi!
>>
>> I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
>> The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:
>>
>> class View {
>> func viewDidLoad() {
>> // does something
>> }
>> }
>>
>> class Button: View {
>> override func viewDidLoad() {
>> super.viewDidLoad() //<— this might be forgotten
>> // do something other
>> }
>> }
>>
>> The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.
>>
>> // Example for extending a function
>> class Button: View {
>> extend func viewDidLoad() {
>> super.viewDidLoad()
>> // do something
>> }
>>
>> extend func viewDidAppear() {
>> // do something
>> } //<— the compiler should throw an error here.
>> }
>>
>> // Example for replacing a function
>> class Geometry {
>> func volume() ->Double {
>> return 0;
>> }
>> }
>>
>> class Cube: Geometry {
>> var length: Double = 0.0
>> replace func volume() ->Double {
>> let v = length * length * length
>> return v
>> }
>> }
>>
>> Cheers,
>> Florian
>>
>>
>>
> _______________________________________________
> 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


(Alexey Demedetskiy) #17

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

In this case you don’t need to write: override(after) func videDidLoad() { … }
Just override will be enough.

but I think they will make the overall system very fragile and inflexible.

override(before), override(after), override(instead) and override affect only one specific function. You cannot constrain child call with it.

Also, simple fix-it should be provided:

1) If no modifiers present and call to super is first call in function --> propose to remove it and add (after) modifier
2) If no modifiers present and call to super is last call in function --> propose to remove it and add (before) modifier
3) If no modifiers present and no call to super in function --> propose to add (instead) modifier
4) If any modifier is present and there is call to super in function body —> propose to remove modifier.

In this case no existing code will be affected of malfunctioning.

···

From my point of view there is no need to add some constraints to childs. There is some cases where this constraints can help,

On Feb 16, 2016, at 4:21 PM, Ross O'Brien <narrativium+swift@gmail.com> wrote:

Jean-Daniel: can you clarify which aspect you're disagreeing with?

For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?

On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

> Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :
>
> Hi
>
> I would like to suggest you to extend your proposal.
>
> In my practice, overriding super functions can have several semantics.
> 1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
> 3) Before super - opposite to 2.
> 4) Override - no rules about order, but super call must be done.
>
> So code can look like:
>
> override(after) func viewDidLoad() {
> // super.viewDidLoad() <— no need to call super at first line.
> // child code
> }
>
> override(before) func tearDown() {
> // clean code
> // super… inserted by compiler
> }
>
> override(instead) func loadView() {
> // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
> }
>
> override func refillHealthBar() {
> // absent call to super will cause an error with fix-up to add (instead) modifier
> }
>
> I am not sure about exposing this in a public interface and limit child override options.
>
> But in general - what is your thoughts about this approach to problem that you mention?
>
>
>> Hi!
>>
>> I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
>> The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:
>>
>> class View {
>> func viewDidLoad() {
>> // does something
>> }
>> }
>>
>> class Button: View {
>> override func viewDidLoad() {
>> super.viewDidLoad() //<— this might be forgotten
>> // do something other
>> }
>> }
>>
>> The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.
>>
>> // Example for extending a function
>> class Button: View {
>> extend func viewDidLoad() {
>> super.viewDidLoad()
>> // do something
>> }
>>
>> extend func viewDidAppear() {
>> // do something
>> } //<— the compiler should throw an error here.
>> }
>>
>> // Example for replacing a function
>> class Geometry {
>> func volume() ->Double {
>> return 0;
>> }
>> }
>>
>> class Cube: Geometry {
>> var length: Double = 0.0
>> replace func volume() ->Double {
>> let v = length * length * length
>> return v
>> }
>> }
>>
>> Cheers,
>> Florian
>>
>>
>>
> _______________________________________________
> 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


(Alexey Demedetskiy) #18

But several attributes can be applied.

1) default - override is enabled in any form. Current default behavior.
2) final - override is disabled in any form. Currently implemented.
3) stub - only override(instead) is allowed. This keyword should mark default bodies.

stub func renderShape(shape: Shape) { }

4) require - override(instead) is disabled. Call to parent is important to the object lifecycle.

This will introduce new keywords, and can be implemented separately from override(…) behavior.
Also instead of ‘stub’ ‘abstract’ can be used.

···

From my point of view, ability to limit behavior in subclasses will do more harm than profit.

Cc:swift-evolution@swift.org
Subject:[swift-evolution] Replace the override keyword by 'extend' and 'replace' or add an annotation like @SuppressSuperCall
Date:February 16, 2016 at 12:28:55 AM GMT+2

+1 for what you outlined Alexey. I think maintaining the use of override as the keyword is the most understandable in the context and also is terminology usually used in various object languages. I like adding the optional qualifiers to allow (1) better diagnostics by the compiler, (2) clearer code, and (3) the opportunity for compiler generating the need coded (in a few of the situations).

Can something like this be used in the super classes interface definition to clarify expectations of a subclass?
On Mon, Feb 15, 2016 at 2:07 PM Alexey Demedetskiy via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> Hi
>
> I would like to suggest you to extend your proposal.
>
> In my practice, overriding super functions can have several semantics.
> 1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
> 3) Before super - opposite to 2.
> 4) Override - no rules about order, but super call must be done.
>
> So code can look like:
>
> override(after) func viewDidLoad() {
> // super.viewDidLoad()<— no need to call super at first line.
> // child code
> }
>
> override(before) func tearDown() {
> // clean code
> // super… inserted by compiler
> }
>
> override(instead) func loadView() {
> // super.loadView()<— marked as an error with appropriate fix-up to remove instead modifier
> }
>
> override func refillHealthBar() {
> // absent call to super will cause an error with fix-up to add (instead) modifier
> }
>
> I am not sure about exposing this in a public interface and limit child override options.
>
> But in general - what is your thoughts about this approach to problem that you mention?
>
>
> >Hi!
> >
> >I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
> >The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:
> >
> >class View {
> >func viewDidLoad() {
> >// does something
> >}
> >}
> >
> >class Button: View {
> >override func viewDidLoad() {
> >super.viewDidLoad() //<— this might be forgotten
> >// do something other
> >}
> >}
> >
> >The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.
> >
> >// Example for extending a function
> >class Button: View {
> >extend func viewDidLoad() {
> >super.viewDidLoad()
> >// do something
> >}
> >
> >extend func viewDidAppear() {
> >// do something
> >} //<— the compiler should throw an error here.
> >}
> >
> >// Example for replacing a function
> >class Geometry {
> >func volume() ->Double {
> >return 0;
> >}
> >}
> >
> >class Cube: Geometry {
> >var length: Double = 0.0
> >replace func volume() ->Double {
> >let v = length * length * length
> >return v
> >}
> >}
> >
> >Cheers,
> >Florian
> >
> >
> >
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution


(Sean Heber) #19

Agreed - attempting to enforce the ordering is too fiddly and complicated, IMO. If the superclass must ensure a specific order, then it should do so itself by first calling a final function that then calls the overridable function at the right time.

Personally I’d like to see the syntax using the “required” keyword that already exists for constructors - so something more like this:

class Base {
  required(super) foo() {
  // etc
  }
}

This would then require any subclasses to call super.foo() if they override foo, but the subclass would not need to do anything new - just use the existing override syntax (with the complier ensuring super is called if it is required).

Then I’d like to see something like this:

class Base {
  required foo()
}

Which implicitly turns “Base” into an abstract base class that cannot be instantiated on its own, but requires a subclass supply a body for the required missing functions.

l8r
Sean

···

On Feb 16, 2016, at 8:43 AM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

I disagree with the introduction of a method to specify if super must be call first or last. Defining that super must be call is fine, but I don’t see why the operation order should be enforced.

If the super class declares a method overridable but require that some code must be perform first, it can simply execute that code before calling the overridable method instead of putting it in the super class definition then force the subclass to call super first.

Moreover, I’m not fond of declaring that requirement in the overriding classes. That is the superclass that should define if a super implementation is required, not the children classes.

Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution <swift-evolution@swift.org> a écrit :

Jean-Daniel: can you clarify which aspect you're disagreeing with?

For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?

On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

> Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org> a écrit :
>
> Hi
>
> I would like to suggest you to extend your proposal.
>
> In my practice, overriding super functions can have several semantics.
> 1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
> 2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
> 3) Before super - opposite to 2.
> 4) Override - no rules about order, but super call must be done.
>
> So code can look like:
>
> override(after) func viewDidLoad() {
> // super.viewDidLoad() <— no need to call super at first line.
> // child code
> }
>
> override(before) func tearDown() {
> // clean code
> // super… inserted by compiler
> }
>
> override(instead) func loadView() {
> // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
> }
>
> override func refillHealthBar() {
> // absent call to super will cause an error with fix-up to add (instead) modifier
> }
>
> I am not sure about exposing this in a public interface and limit child override options.
>
> But in general - what is your thoughts about this approach to problem that you mention?
>
>
>> Hi!
>>
>> I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
>> The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:
>>
>> class View {
>> func viewDidLoad() {
>> // does something
>> }
>> }
>>
>> class Button: View {
>> override func viewDidLoad() {
>> super.viewDidLoad() //<— this might be forgotten
>> // do something other
>> }
>> }
>>
>> The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.
>>
>> // Example for extending a function
>> class Button: View {
>> extend func viewDidLoad() {
>> super.viewDidLoad()
>> // do something
>> }
>>
>> extend func viewDidAppear() {
>> // do something
>> } //<— the compiler should throw an error here.
>> }
>>
>> // Example for replacing a function
>> class Geometry {
>> func volume() ->Double {
>> return 0;
>> }
>> }
>>
>> class Cube: Geometry {
>> var length: Double = 0.0
>> replace func volume() ->Double {
>> let v = length * length * length
>> return v
>> }
>> }
>>
>> Cheers,
>> Florian
>>
>>
>>
> _______________________________________________
> 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


(Sean Heber) #20

It occurs to me that “required(super)” is probably unnecessary - just use “required” on any function where an override must call super and leave it off on any function that doesn’t need to call super on an override. For any function that is illegal to override, we already have “final” for that. Additionally, if “required” exists on a function with no body implemented, then that turns the entire class into an abstract base class and subclasses must supply the body and *not* call super (since the base class obviously has no implementation itself).

I’m probably missing something somewhere, but that seems like it’d cover the important cases - all without adding any new keywords or even any new variations on existing keywords.

l8r
Sean

···

On Feb 16, 2016, at 8:51 AM, Sean Heber <sean@fifthace.com> wrote:

Agreed - attempting to enforce the ordering is too fiddly and complicated, IMO. If the superclass must ensure a specific order, then it should do so itself by first calling a final function that then calls the overridable function at the right time.

Personally I’d like to see the syntax using the “required” keyword that already exists for constructors - so something more like this:

class Base {
required(super) foo() {
  // etc
}
}

This would then require any subclasses to call super.foo() if they override foo, but the subclass would not need to do anything new - just use the existing override syntax (with the complier ensuring super is called if it is required).

Then I’d like to see something like this:

class Base {
required foo()
}

Which implicitly turns “Base” into an abstract base class that cannot be instantiated on its own, but requires a subclass supply a body for the required missing functions.

l8r
Sean

On Feb 16, 2016, at 8:43 AM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

I disagree with the introduction of a method to specify if super must be call first or last. Defining that super must be call is fine, but I don’t see why the operation order should be enforced.

If the super class declares a method overridable but require that some code must be perform first, it can simply execute that code before calling the overridable method instead of putting it in the super class definition then force the subclass to call super first.

Moreover, I’m not fond of declaring that requirement in the overriding classes. That is the superclass that should define if a super implementation is required, not the children classes.

Le 16 févr. 2016 à 15:21, Ross O'Brien via swift-evolution <swift-evolution@swift.org> a écrit :

Jean-Daniel: can you clarify which aspect you're disagreeing with?

For example: should standard library types prefer the 'override' form which enforces calling super but doesn't enforce when it is called?
Perhaps 'override(before)' should be an indication that, if the overriding method doesn't explicitly declare the super call, then it should be called implicitly at the start of the function?

On Tue, Feb 16, 2016 at 2:12 PM, Jean-Daniel Dupas via swift-evolution <swift-evolution@swift.org> wrote:

-1 for enforcing the super call place.
While we usually call super at the beginning of viewDidLoad for instance, there is absolutely no need to enforce it and it may result in problem when some work have to be done before the super method is executed.

I have some use cases that rely on performing setup before calling the super.viewDidLoad().

Le 15 févr. 2016 à 23:06, Alexey Demedetskiy via swift-evolution <swift-evolution@swift.org> a écrit :

Hi

I would like to suggest you to extend your proposal.

In my practice, overriding super functions can have several semantics.
1) Replace - simple case for abstract classes which implementation do nothing, or throw an exceptions.
2) After super - things like viewDidLoad and viewWillAppear, setUp etc. All cases where super expect to be called before child code.
3) Before super - opposite to 2.
4) Override - no rules about order, but super call must be done.

So code can look like:

override(after) func viewDidLoad() {
  // super.viewDidLoad() <— no need to call super at first line.
  // child code
}

override(before) func tearDown() {
  // clean code
  // super… inserted by compiler
}

override(instead) func loadView() {
  // super.loadView() <— marked as an error with appropriate fix-up to remove instead modifier
}

override func refillHealthBar() {
// absent call to super will cause an error with fix-up to add (instead) modifier
}

I am not sure about exposing this in a public interface and limit child override options.

But in general - what is your thoughts about this approach to problem that you mention?

Hi!

I would like to suggest to replace the override keyword for functions by something like extend and replace or to add an annotation like @SuppressSuperCall (don’t know a good name for it).
The reason for this is, that it might happen, that one forgets to call the super’s implementation in an overridden function or if one reads the code it might not be obvious why the super’s implementation is not called:

class View {
func viewDidLoad() {
// does something
}
}

class Button: View {
override func viewDidLoad() {
super.viewDidLoad() //<— this might be forgotten
// do something other
}
}

The compiler will accept if one overrides a superclass’s function but does not call the superclass’s implementation which is often ok. The developer should clearly state that he doesn’t want to call the superclass’s implementation, otherwise the compiler should throw an error.

// Example for extending a function
class Button: View {
extend func viewDidLoad() {
super.viewDidLoad()
// do something
}

extend func viewDidAppear() {
// do something
} //<— the compiler should throw an error here.
}

// Example for replacing a function
class Geometry {
func volume() ->Double {
return 0;
}
}

class Cube: Geometry {
var length: Double = 0.0
replace func volume() ->Double {
let v = length * length * length
return v
}
}

Cheers,
Florian

_______________________________________________
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