Overriding function in sub interface with implementation returning "Nothing" changes return type to "Nothing"


#1

Hi,

If I define the following two interfaces:

interface Parent {
    fun value(): List<String>
}

interface Child : Parent {
    override fun value() = throw IllegalStateException()
}

And then try to implement interface Child:

object ChildImplementation : Child {
    override fun value() = listOf("A value")
}

The compiler compains: Return type of ‘value’ is not a subtype of the return type of the overridden member ‘public open fun value(): Nothing defined in …Child’

Is this the expected behavior? I would assume that overriding a function does not allow you to change its return type (except when you change it to a covariant type).


#2

Nothing is the subtype of all Kotlin types, so this is in fact a covariant override.


#3

Ah, I see. I had not found that information.

Unfortunately now I have to use a longer notation for the same thing. If I put the throw in a function, I could write:

fun somethingSpecial() = throw IllegalStateException()

interface Child : Parent {
    override fun value() = somethingSpecial()
}

But now I have to write the following. The function only has to be written once, so that is not a problem, but I would prefer not having to repeat the type of the list elements:

fun <T> somethingSpecial() : List<T> = throw IllegalStateException()

interface Child : Parent {
    override fun value() = somethingSpecial<String>()
}

Is there any way I could use something short without changing the return type, and without implementors of the interface having to implement the function?


#4

This problem is covered by the issue https://youtrack.jetbrains.com/issue/KT-11684


#5

Good to see that it already has been reported. I voted for it, and I am now postponing all development until Kotlin 2.0 :wink:


#6

Why not explicitly define the return type. That should not cause a problem either and is far less clunky.


#7

It is part of a DSL, and the return type is noise at that point. Here is an example that will hopefully clarify the need a bit:

class Component(private val provided: Provided) {
    interface Provided : SubComponent.Provided {
        override fun someService(): SomeService = providedByMe()
        fun anotherService(): AnotherService
    }
    fun subComponentCreator() =
        SubComponent(object : Provided by provided {
            override fun someService() = getAnInstanceOfSomeServiceFromSomewhere()
        })
    ...
}

If somebody wants to use Component, then they no longer have to implement someService():

Component(object : Component.Provided {
     override fun anotherService() = ...
     // Function overrides for functions of "SubComponent.Provided"
     // not overridden by "Component.Provided".
})

So in Component.Provided the only information I want to communicate is that an instance of SomeService will be provided by Component. At that point it serves no purpose to communicate the return type again. I also do not want the return type changed to a covariant type, because I intend to override the function later and want to return an instance of the original type then.