Kek
Kek

Reputation: 381

Is there a way to get the type of object that inherits an interface (or another class) in Kotlin?

I've got an interface IMyInterface with a method

fun myMethod(thing: T){}

I also have a class

class MyClass : IMyInterface{}

What I want is that when I implement the members of the interface it automatically sets the type T to be MyClass. Is there a way of doing that? So, instead of writing

    interface IMyInterface <T>{
fun myMethod(thing: T){}
}

class MyClass: IMyInterface<MyClass>{
  override fun myMethod(thing: MyClass){} // <<<-- the type is set because I explicitly set it above
    }

I want to have something like this:

interface IMyInterface{
fun myMethod(thing: T){}
}

class MyClass: IMyInterface{
  override fun myMethod(thing: MyClass){} // <<<-- the template type <T> of the interface is resolved by the compiler by checking what type I provided in method signature (
    }

Or maybe getting a type of the class implementing an abstract class.

Upvotes: 0

Views: 64

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170713

There is another problem which Thomas Cook's answer doesn't cover: even if this was possible, you run into major problems with subtyping in at least two ways.

Let's assume a keyword Self which means what you want and

interface IMyInterface{
    fun myMethod(thing: Self): Unit
}

Problem 1: You have a val x: IMyInterface = ... What can you pass to x.myMethod? Certainly not any IMyInterface, that would defeat the purpose. But the only thing which is guaranteed to have the same concrete type as x is... x (assuming no Self-returning methods).

Problem 2: Add class MySubClass : MyClass. It must have override fun myMethod(thing: MySubClass), right? But it also has to inherit override fun myMethod(thing: MyClass) from MyClass.

Upvotes: 0

Thomas Cook
Thomas Cook

Reputation: 4853

What you are wanting to do is not possible. You want the compiler to "Magically" figure out what the template parameter is... think about it; how would it know - there is a potentially infinite subset of IMyInterface. It is not implied in your interface that the template type <T> is even of type IMyInterface, so it could literally be any type...

Here is another angle on the problem that may make it clear why the compiler cannot do this:

// The same interface as your example, but with extra method
interface IMyInterface{
   fun myMethod(thing: T){}
   fun myOtherMethod(thing: T){}
}

// The same implementation as before, except the extra method is overridden with a different type than the first method
class MyClass: IMyInterface{
  // the template type <T> of the interface is resolved by the compiler by 
  // checking what type I provided in method signature (this is what you want compiler to do)
  override fun myMethod(thing: MyClass){}

  // Uh oh! How does the copmpiler resolve this? We just figured out that <T> was my class. 
  // So this method won't compile... why not just tell entire class what <T> is 
  // rather than trying to make all method signatures match up so the compiler can "infer" the type???
  override fun myOtherMethod(thing: MyOtherClass) {} 
}

class MyOtherClass : IMyInterface {
   override fun myMethod(thing: MyOtherClass) = this
   override fun myOtherMethod(thing: MyOtherClass) = this
}

Upvotes: 1

Related Questions