Return type inferred from the lambda parameter return type

I’m wondering if there is any way how Kotlin can infer the return type of the function based on its lambda parameter. I have the following code in Java:

private Map<Class<?>, Object> map = new HashMap<>();

private <T> T getInstance(Class<T> clazz) {
    Object value = map.get(clazz);
    return (T)value;
}

public <T, R> R process(Class<T> clazz, Function<T,R> f) {
    T instance = getInstance(clazz);
    return f.apply(instance);
}

@Test
public void testFoo() {
    map.put(Integer.class, 42);
    double doubleValue = process(Integer.class, x -> x + 13.2);
    System.out.println("Got double result "+doubleValue);
}

This works nicely and I’m trying to recreate a similar thing in Kotlin. This is what I have so far

var map = mapOf<KClass<out Any>, Any>().toMutableMap()

fun <T : Any> getInstance(clazz : KClass<in T>) : T {
    val instance = map[clazz]
    if (clazz.isInstance(instance)) {
        return instance as T
    } else {
        throw IllegalArgumentException("No instance for $clazz")
    }
}


inline fun <reified T : Any, R> process( noinline f : (T) -> R): R {
    val instance = getInstance(T::class)
    return f(instance)
}

class Test {
    @Test
    fun test() {
        map.put(Integer::class, 42)
        val doubleValue = process<Integer, Double> { it.toDouble() + 13.2 }
        println("Got double result $doubleValue")
    }
}

Now this works great, but I would like to make it even better - ideally I would like to omit the requirement to specify the output type in the process function - so instead of writing
val doubleValue = process<Integer,Double> { it.toDouble() + 13.2 }
I would like to write just
val doubleValue = process<Integer> { it.toDouble() + 13.2}
and infer the return type from the return type of the lambda itself. Is this doable? Thoughts? Ideas?

Tried adding reified to R?

That doesn’t help - the reification of the type is not really needed in this case.

Try currying it. Your process function would have just one type parameter. It would return another function, which has the second type parameter. Just an idea, didn’t try it.

Maybe something like this could work (still didn’t try it, just an idea):

inline fun <reified T : Any> process() :  Processor<T> {
    return Processor(getInstance(T::class))
}
class Processor<T>(private val value: T) {
    operator fun <R> invoke(f: (T) -> R) = f(value)
}

You might need to invoke it with implicit parenthesis like so:

process<Integer> () ({
    it.toDouble() + 13.2
})

I don’t know whether it will be parsable without the parenthesis.

Indeed, the problem is that the option is either inference, or explicit parameters, but not combination. The following call should also work (of course you now might want to rename it):

val doubleValue = process { it:Int -> it.toDouble() + 13.2}