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

I think there are 2 things needed here. As @mikehearn pointed out it would be nice to have an annotation which would ensure the compiler checks that super() gets called.

I do not however think that this could or should replace runtime checks ( or at least not in critical places). As long as code get’s used outside of kotlin such an annotation would most likely be only checked by the kotlin compiler and therefor not guarantee to enforce the call at all times.
Still I think an annotation like this would be a good idea.

As for a shorthand to call the super implementation I’m not sure how I would like to see this done. I agree, that this would be really helpful in case of many arguments. I like @dalewking’s idea of using by super. The problem with this as some people pointed out is that in many cases you want to access the return value of the super call. I would argue for just using it and giving the option of renaming it the same way someone would do using a lambda.

override fun foo(i: Int): Int by super() { result -> println(result) }

Also I wanted to add, that at least the annotation could be resolved using a compiler plugin (once JetBrains releases a stable version of the API). As some people have pointed out the need for this mostly stems from some bad code design in Android and I am not sure if I want this feature as part of Kotlin as it would probably lead to more bad code. So maybe a compiler plugin would be a good alternative. When programming for android it would not be to much to ask to enable this plugin, thereby getting the usage of the annotation, without adding this annotation as a language feature, which can not be fully enforced anyways.


I am not sure if I am fully qualified for or against this. Obviously the decorator pattern is not bad code design and also the need to call a super implementation is not necessarily, but I am also a fan of the template method @medium pointed mentioned, which can be changed to use empty methods instead. I’m not an android developer so I am not an expert on this, but I think the problem with this and android is the method count limit, but I don’t really know how severe this so yeah, I wont judge android on it’s API choices as I don’t know enough about them.

I would like this feature very much.
I’m not an android developer, so I was not aware of @CallSuper and now I want to have it in std-lib :slight_smile: .

This could be a simple and light-weight event pattern.

It’s not necessarily bad OOP style to require overrides to call the superclass, but it is a somewhat clumsy workaround to a deficiency in the language.

The base class declares that the method can be overridden, i.e., that a subclass can provide a new implementation, but that is not what the designer wants. The intent is that the base class can extend the method, like adding a listener to an existing event. Since it’s impossible to say declare this, we get “you can override the method, but you have to follow this ritual to ensure that my implementation still gets called”.

If Kotlin wants to fix this in the language, the best solution is not to add sugar to make the supercall ritual easier to follow. They should add the desired kind of inheritance instead, like:

open class Base {
    extensible fun close(arg: SomeArg) : SomeResult {
        // ...
    }
}
class Derived {
    extend fun close(arg: SomeArg, result: SomeResult?) {
        // ...
    }
}
2 Likes

I don’t know how necessary such a language-level solution is when one can just do it manually with minimal boilerplate. This especially is important because sometimes one doesn’t want to use a SomeResult from the super method, and instead wants the super method to be able to modify the result of the child method:

open class Base {
    fun close(arg: SomeArg) : SomeResult {
        // Some code here
        val result = ...
        return doClose(arg, result)
    }
    protected open fun doClose(arg: SomeArg, result: SomeResult): SomeResult = result
}
class Derived {
    override fun close(arg: SomeArg, result: SomeResult): SomeResult {
        // ...
    }
}