Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write lambdas with generics in kotlin?

I can write lambdas id_Int and id_Boolean with explicit type. And I can write function identity with type parameter. Can I write lambdas with type parameter?

fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2

val id_Int = { x: Int -> x }

fun testFuncBoolean(f: (Boolean) -> Boolean): Boolean = !f(false)

val id_Boolean = { x: Boolean -> x }

fun <T> identity(x: T) = x

fun main(args: Array<String>) {
    println(testFuncInt(id_Int))
    println(testFuncInt(::identity))
    println(testFuncBoolean(id_Boolean))
    println(testFuncBoolean(::identity))
}
like image 225
xiang Avatar asked Jul 03 '17 07:07

xiang


People also ask

How do you write generic method Kotlin?

Kotlin generic extension function example As extension function allows to add methods to class without inherit a class or any design pattern. In this example, we add a method printValue()to ArrayList class of generic type. This method is called form stringList. printValue() and floatList.

What is () -> unit in Kotlin?

Unit in Kotlin corresponds to the void in Java. Like void, Unit is the return type of any function that does not return any meaningful value, and it is optional to mention the Unit as the return type. But unlike void, Unit is a real class (Singleton) with only one instance.

How do I create a generic object in Kotlin?

How can I idiomatically achieve this in Kotlin? You need to pass a KClass<out Cell> as a constructor parameter to CellList , and to invoke the constructor using reflection. You can also create a factory function with a reified type parameter to enable creating CellList instances with a somewhat cleaner syntax.


3 Answers

Kotlin does not have support for declaring generic properties without declaring that type at class level (see also), but you can do it using a function that returns a lambda corresponding to the desired type:

fun main(args: Array<String>) {
    println(testFuncBoolean(id()))
    println(testFuncInt(id()))
}

fun <T> id(): (T) -> T = { it }

fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2
fun testFuncBoolean(f: (Boolean) -> Boolean): Boolean = !f(false)
like image 115
Christian Brüggemann Avatar answered Oct 11 '22 05:10

Christian Brüggemann


You can not write lambda with generics, why following paragraph taken from official documentation says it all.

A lambda expression or an anonymous function is a "function literal", i.e. a function that is not declared, but passed immediately as an expression

A lambda expression or function is not declared, its an anonymous function.

But ultimately we do same thing by declaring function type as generic. We can pass a lambda expression that does the job.

fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2 

you can call it like: testFuncInt{ a -> a } or testFuncInt{ it }

So finally you are doing same thing (lambdas with type parameter), but there is no term like that as lambdas are expressions or anonymous functions.

Hope it helps.

like image 31
chandil03 Avatar answered Oct 11 '22 05:10

chandil03


No, but you generally don't need to. A lambda has no declaration (which is kind of the point), so it's essentially an expression you can pass to a function, store in a val/var as you did when doing val id_Boolean = { x: Boolean -> x } but the type really gets worked out as it would in an expression.

The calls here will resolve to the correct type, since your functions takes a function that takes an Int and returns an Int, and a function that takes a Boolean and returns a Boolean

testFuncInt({ x -> x }) // x is an Int
testFuncInt({ it })     // it is the default argument
testFuncInt { x -> x }  // as top one, Kotlin's syntactic sugar

The important thing here is that the lambda expression still offers type safety, i.e. if you did something like this

fun <T> foo(x: T, lambda: (T) -> Boolean): Boolean = lambda(x)
foo(42, { x -> x })   // oops, lambda takes a T and returns a T

this will trigger a compiler error as lambda's types don't match what foo expects, i.e. foo will pass an Int to the lambda and it expects a Boolean back. On the other hand, if you do this

foo(123, { it == 42 })
foo(123) { it == 42 }   // equivalent to above

The return type is actually deduced to be a Boolean as that's what the result of a comparison operation evaluates to and as 123 and 42 are of the same type, lambda's types actually fit into what foo expects.

like image 36
Andrej Avatar answered Oct 11 '22 06:10

Andrej