A function with generic return type

Viewed 10115

Is it possible to have a function that returns a generic type? Something like:

fun <T> doSomething() : T {
    when {
        T is Boolean -> somethingThatReturnsBoolean()
        T is Int -> somethingThatReturnsInt()
        else -> throw Exception("Unhandled return type")
    }
}
4 Answers

Any might be something you want to use. It's the root of Kotlin class hierarchy.

Also optional is available for Any with the syntax Any?

fun doSomething(key: Any): Any {
    when {
             key is Boolean -> return true
             key is Int -> return 1
             else -> throw Exception("Unhandled return type")
         }
}

You could also directly pass your functions like somethingThatReturnsInt() etc. to a generic function and infer the return type from the passed function itself. Here is an example for Kotlin:

// This function takes any method you provide and infers the result-type
public fun<T> generic_function(passed_function: () -> T): T? =
    passed_function()


// Pass your function. The return type will be inferred directly from somethingThatReturnsInt()'s return-type
val res: Int? = generic_function(::somethingThatReturnsInt)

// For the sake of completeness, this is valid as well
val res: Int? = generic_function<Int?> { somethingThatReturnsInt() }

This way you don't have to deal with when-scenarios and your return-type is generic depending on the passed function.

Well, there is a way to do something like this, but it feels a bit hacky:

data class Coffee(val milk: Double, val sugar: Int)

class ComparingBuilder(val oldInstance: Coffee, val updatedInstance: Coffee) {
     operator fun <T> invoke(accessor: Coffee.() -> T?): T? =
         if (whatever) { oldInstance.accessor() }
         else { updatedSupplier.accessor() }
}

fun useComparingBuilder(
    oldInstance: Coffee,
    updatedInstance: Coffee,
) = OptionalBuilder(oldInstance, updatedInstance).let { builder ->
    val remixedCoffee = Coffee(
        milk = builder { milk },
        sugar = builder { sugar },
    )
}

So, in short, no, this isn't a way to make a generic lambda - but it's a way to make something that can use something as if it were a generic lambda.

Struggling to put this into words; I hope the code is clearer....

Related