Parameter defaulting in function overwriting

When overwriting a function apparently I cannot force the caller to provide parameters, when these are defaulted in the underlying abstract class. May be that’s by language design intention or may be not. I’d like to hear any comments on that and the rationales behind this.

In the following example my intention is that the audience MUST tell the OperaMusician explicitly what to sing. Instead they are able to ask him just to sing something and via the parameter defaulting he picks something unexpected.

fun main() {
OperaMusician().play(“Largo al factotum”)
OperaMusician().play()
}

abstract class GeneralMusician {
open fun play(song:String = “Oups, I did it again”) {}
}

class OperaMusician: GeneralMusician() {
override fun play(song:String) {
println(“singing: $song”)
}
}

A general principle with inheritance is the Liskov substitution principle, which in simple words says that an OperaMusician should be useable wherever a GeneralMusician is expected. Hence, how would you expect this code to function?

val musician: GeneralMusician = OperaMusician()
musician.play()

One trick you can do is hide the overridden function, and instead provide one with a similar signature but no defaults as an extension:

fun main() {
    OperaMusician().play("Largo al factotum")
    OperaMusician().play()
}

abstract class GeneralMusician {
    open fun play(song:String = "Oups, I did it again") {}
}

class OperaMusician: GeneralMusician() {
    @Deprecated("", level=DeprecationLevel.HIDDEN)
    override fun play(song:String) {
        println("singing: $song")
    }
}
fun OperaMusician.play(song: String) = (this as GeneralMusician).play(song)

of course! :man_facepalming:.
Thanks for the quick response. May this be a lesson for myself and everybody else, who haven’t done their theory homework properly first.
Roland

1 Like