1

Expect you have an interface like this:

interface MyInterface<T : BaseClass<I>, I> {
    fun someMethod(param: I) : T
}

As you can see I use I as a parameter in someMethod. But actually I don't want to declare I when I implement this interface like this:

class BaseClassImpl : BaseClass<OtherClass>

class Impl : MyInterface<BaseClassImpl, OtherClass> {
    override fun someMethod(param: OtherClass) {
        TODO("Not yet implemented")
    }
}

Theoretically it should be possible that the I generic can be resolved by the compiler without the additional declaration because it's provided by BaseClassImpl. So MyInterface<BaseClassImpl> should already provide enough information to resolve the necessary generic for someMethod().

Is there any way to achieve that in Kotlin?

Marcus Held
  • 635
  • 4
  • 15

2 Answers2

2

It's impossile in Kotlin. Language specification states:

There are two kinds of type inference supported by Kotlin.

  • Local type inference, for inferring types of expressions locally, in statement/expression scope;
  • Function signature type inference, for inferring types of function return values and/or parameters.

It can't infer type of one generic parameter based on the type of another (especially for supertype declaration, because it is a very base for building type constrains system).

You may declare typealiases (for each T) to avoid repating I each time you implement this interface:

typealias MyInterfaceForBaseClassImpl = MyInterface<BaseClassImpl, OtherClass>

class Impl : MyInterfaceForBaseClassImpl {
    override fun someMethod(param: OtherClass) : BaseClassImpl {
        //...
    }
}
  • Thanks for your answer. The typealias can make it easier when I have to implement a specific combination of this interface multiple times. But actually I will have a lot of different `T` and `I` variations and I guess I need to bite the bullet then. – Marcus Held Feb 19 '21 at 07:42
0

It is not about compiler resolving, but about enforcing, when you declare interface MyInterface<T : BaseClass<I>, I : OtherClass> , declaration expects two parameters, May be you can create OtherInterface with OtherClass embedded and use it while implementing instead of MyInterface

interface BaseClass<I: OtherClass>
interface OtherClass

interface MyInterface<I : OtherClass, T: BaseClass<I>> {
    fun someMethod(param: I)
}

class BaseClassImpl: BaseClass<OtherClass>

interface OtherInterface<T: BaseClass<OtherClass>> : MyInterface<OtherClass, T>

class Impl : OtherInterface<BaseClassImpl> {
    override fun someMethod(param: OtherClass) {

    }
}
Rajan Kali
  • 12,627
  • 3
  • 25
  • 37
  • I noticed that I had an error in the declaration of the interface. `I` actually don't derive from `OtherClass` but `I` can be any class. Because of that your solution don't solves it since I'd need to declare the intermediate interface for any possible implementation. – Marcus Held Feb 18 '21 at 12:48