Is there a neat trick to have both reified and inf...
# announcements
r
Is there a neat trick to have both reified and inferred type parameters on the same function? It seems the moment I have to provide one I have to provide all, which is making me sad.
r
Can you give an example of what you mean?
z
Reified type parameters can be inferred. However, reified or not, kotlin cannot only infer a subset of the parameters.
Makes me sad too
y
Well there is a bit of a trick for it depending on how your function is structured. What I do is define a sealed class with out parameters named
TypeWrapper
and then I have only one instance of it which has Nothing for all the type params, then I have functions that "construct" a
TypeWrapper
named
type
that basically just return that one instance, but basically this forces the compiler to carry that type information around. Then, I make my functions either extensions on TypeWrapper or take in a parameter of it and then use its type params. I realise that this is very hard to explain in text so just give me one second and I'll find my like 100 line code with all the definitions and demonstration of how it works, but tbh it is a very neat trick that does the job
Here we go I finally found it: https://pastebin.com/STrFiCji (it was too long to paste in Slack lol). Please note that obviously this is a bit over-the-top and if you have a simple use case like needing 2 type parameters to be specified and the rest to be inferred then you can write the definition like:
Copy code
sealed class TypeWrapper<out T1, out T2> {
    @PublishedApi internal object Impl: TypeWrapper<Nothing, Nothing>()
}
inline fun <T1, T2> type(): TypeWrapper<T1, T2> = TypeWrapper.Impl
and now, for the most important piece of all, this is how the callsite looks like (playground):
Copy code
inline fun <reified T1, T2, reified R> TypeWrapper<T1, T2>.myFun(param1: Any, param2: R): String = param1.toString() + param2 + T1::class + R::class

fun main() {
    println(type<Int, Boolean>().myFun("Hello", " World"))
}
or alternatively if you already have an extension receiver (playground):
Copy code
inline fun <reified T1, T2, reified R> Any.myFun(param2: R, type: TypeWrapper<T1, T2>): String = toString() + param2 + T1::class + R::class

fun main() {
    println("Hello".myFun(" World", type<Int, Boolean>()))
}

sealed class TypeWrapper<out T1, out T2> {
    @PublishedApi internal object Impl: TypeWrapper<Nothing, Nothing>()
}
inline fun <T1, T2> type(): TypeWrapper<T1, T2> = TypeWrapper.Impl
r
Thanks Youssef, that’s very interesting (& clever!)