Add a concise way to specify that an override method should call the super method

In Android there are lots of methods where you override a method in the superclass, but are required to call the super class implementation (it is checked to make sure you did). So you have many methods that look something like this:

override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?)
{
    super.onSaveInstanceState(outState, outPersistentState)
    
    doSomething()
}

Which is a lot of ceremony and duplication of variable and function names and it prevents you from doing things like using an expression body for the method.

I find myself wishing if Kotlin had some shorthand you could add to the method signature to tell the compiler to generate the call to the super implemenation for me.

Not sure what the syntax of that might be, but would probably involve the word super somewhere. One thought I had was that it would kind of be like class delegation and property delegation so perhaps something using the by keyword might be a good start:

   override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?)
      by super = doSomething()

This could also support parameters to super if you want to pass something other than the actual parameters

override fun foo(a:Int) by super(a+1) { }

But there could be some ambiguity if the method parameter were a function and knowing if the braces were a lambda to pass to super or the body of this method. That could be solved by requiring the parentheses on super. The super would act like function with all parameters defaulted to the parameters passed to this implementation so that if the method had multiple parameters and you only wanted to change some you could use named arguments:

override fun baz(a: Int, b:Int) by super(b = 5) { }

would be equivalent to

override fun baz(a: Int, b:Int) = super.baz(a, 5)

But then how do you access the return value of the super call? Perhaps the body is then looked at as a lambda and the result of the super call is passed as a parameter.

4 Likes

I’d rather just have a shorthand for the supercall itself, i.e. “super()” by itself is an expression that evaluates to a call to the parent method of the same name with the same arguments.

But this is just a tiny bit of syntax sugar. What I’d really like to see here is a method annotation that states an overriding method must call the superclass, checked by the compiler. It sucks that Android needs tons of runtime checks to ensure you didn’t forget to do this - that’s exactly what type systems are for. If it was an annotation, it could be added to the Android APIs directly on the Java side, with an external annotations file used in the meantime. Although adding it to APIs like that would not be backwards compatible, any code that broke would be guaranteed to be buggy.

6 Likes

I thought about something like that and rejected it because you get into ambiguities. What if the super class uses operator overloading with an invoke function? Does this mean to invoke the invoke operator or to call the super class implementation of this method.

There could possibly be some syntax to distinguish the two, but it cannot just be super() inside the method.

And your way only takes care of the name duplication and not the ability to use expression body for the method.

I can understand that you would like to have such a shorthand, but from my point of view this need arises due to bad OOP style of Android. Preferably a derived class should not call the base class.

The need to call a super class implementation is not bad OOP style at all and is in no way specific to Android. The decorator pattern is based on this idea.

Kotlin already requires keyword open on methods that can be overridden. Why not have two keywords, one for “override in whichever way you want” (e.g. the current open) and another for “overriding implementations need to call super” (e.g. important)?

2 Likes

The nice thing about using annotations rather than new keywords is that you can externally annotate other APIs, so then kotlin users can get the benefits without needing the external API to be updated.

I realize now that my subject for the thread was a little ambiguous. I was not looking for a way to annotate the definition of the method in the superclass to force any overrides of the method to include a call to the super class method. That may be valuable too, but not what I was after. I was looking for a concise way for the overriding method to make the call to the super method.

A function/method annotation specifying that implementations in subclasses must chain up would be very useful.

1 Like

Android actually has a way to enforce this: CallSuper  |  Android Developers

If a method is annotated with “CallSuper”, then the linter ensures that a super call takes place in the overriding method, else it will fail the build.

It would be nice if Kotlin had a similar annotation or keyword and compiler check for non-Android projects.

1 Like

If you want concise, and subclasses are supposed to always call the super method, then it makes more sense to use two methods instead, e.g.

fun publicMethod() {
    someStandardCode();
    overriddenCode();
}

abstract protected fun overriddenCode();
1 Like

Too bad you can not change the android api :stuck_out_tongue:

Hi all, no news on this? I think it is a good idea, it will make the code cleaner, specially in android. It could be also:
override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) : super
{
doSomething()
}

Instead of forcing the subclass to call its parent, the parent class could define an abstract method that gets called by the super class. Basically the super class would control the flow instead of the sub class.

This pattern is known as template method.

Nope, the colon is already used to designate the type of the result returned by the function.

@jstuyts you are right, but I think using the reserved word super the return type can be hidden, due to it will be always the same than the parent.

But then your are using super for 2 purposes:

  • The return type of this overriding function is the same as the function it overrides. This functionality has already been requested here: https://youtrack.jetbrains.com/issue/KT-11684
  • The function will call the overridden function before executing its own method.

I think these 2 should have different language constructs.

@jstuyts sounds reasonable, the signature should be clear and not having more than one meaning. Then it could be as the original post here, using by super for supercalls, and super for supertype as described at KT-11684

And is not applicable here. Usually a good idea to read the thread before replying.

That forces the subclass to override those methods and we are talking dozens of methods. The intent is not to force subclasses to override the methods but to easily allow subclasses that do override the methods to call the superclass implementation, because it is required by Android that when you override that you do call the super method (it checks this).

And besides we are talking about an existing Java API that isn’t going to be changed.

1 Like

Not actually true. You can and often it is useful to override a method and return a more specific type than the parent declares:

       open class SuperClass
       {
            open fun doSomething(): CharSequence = "foo" 
       }

    class SubClass : SuperClass()
    {
        override fun doSomething(): String = "bar"
    }
1 Like