1

If I have a class like the following:

class SimpleClass {
    var test: Int = 1
}

I can do something like this:

inline fun <reified T : SimpleClass> myFunction1(): T {
        //Do something with T
}

But if I have a class with generics:

class ComplexClass<T> {
    var test: T? = null
}

How can I do the same?

The following doesn't work:

inline fun <reified T : ComplexClass<C>> myFunction2(): T {
        //Do something with T
        //Do something with C
}

How can I do it?

Here is a more complex example, if needed.

ᴜsᴇʀ
  • 1,109
  • 2
  • 9
  • 23
  • 1
    `reified` is a modifier for inline functions. Nothing more. – Agent_L Dec 19 '22 at 10:58
  • What are you trying to do specifically? Do you have a concrete example? – Joffrey Dec 19 '22 at 11:21
  • @Joffrey I want to use `myFunction2` in a class with a variable return type, and this class use generics. [Here](https://pastebin.com/raw/Tr1SchxA) is a more complete example. – ᴜsᴇʀ Dec 19 '22 at 11:55

1 Answers1

1

Let's take a look at your example

class Mediator {
    //It does't work! My question is about this function.
    inline fun <reified T : Container<C>> mediate(string: String): T {
        if (C::class == Child1::class)
            //Do something
        if (C::class == Child2::class)
            //Do something else
    }
} 

class UseExample : Mediator() {

    fun example1(): Container<Child1> {
        return mediate("test1") // your mediate function does not take
        // any parameters to determine the generic type
    }

    fun example2(): Container<Child2> {
        return mediate("test2")
    }
}

To perform something with the type C which is used to create Container<C> and perform something with the result type which you represent as T : Container<C> you only need to know the C. Since reified can only be used to keep the type if it is known during the compile time at the call site, rewrite your function signature like this.

inline fun <reified C> mediate(string: String): Container<C> {
   // now you know the C and you know the T which is Container<C>
   if (C::class == Child1::class) ...
   // Since T depends on C, you can only check the C type to perform logic
}

Use it like following

fun example1(): Container<Child1> {
    return mediate<Child1>("test") // Note that know your C 
    // type is known at the function call therefore compiler 
    // can substitute it with exact type
}

Here is my minimal example from Kotlin Playground

class Container<T>(t: T) {
    val smth : T = t
}

class Mediator {
    inline fun <reified C> mediate(string: String): Container<C> {
         if (C::class == Int::class) {
             println("Int")
             return Container<Int>(1) as Container<C>
         }

         throw IllegalStateException("Yopta")
     }
}


fun main() {
    val m = Mediator()

    m.mediate<Int>("ABC") // Output is "Int"
}
Steyrix
  • 2,796
  • 1
  • 9
  • 23
  • It works as I wanted, thanks. Further addition: what if the `T` in `Container` is a `Array`? Ho can I get `Child1` instead of `Array` in the mediate function? The check `C::class == Array::class` fails. – ᴜsᴇʀ Dec 19 '22 at 16:12
  • `Array` will have combined `::class`. So probably `Array::class` will do the work. If it will not, try by checking element's type – Steyrix Dec 19 '22 at 19:20