Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function References and lambdas

Tags:

kotlin

I'm facing a compile error when trying to use lambdas / function references with kotlin:

class Foo {

    fun getFilteredList(){
        val numbers = listOf(1, 2, 3)
        numbers.filter(::isOdd) // prints [1, 3]
    }

    fun isOdd(x: Int): Boolean = x % 2 != 0

}

But I get a compile time error saying a type mismatch:

Error:(18, 16) Gradle: Type inference failed: inline fun kotlin.Iterable.filter(predicate: (T) -> kotlin.Boolean): kotlin.List cannot be applied to receiver: kotlin.List arguments: (kotlin.reflect.KFunction2) Error:(18, 23) Gradle: Type mismatch: inferred type is kotlin.reflect.KFunction2 but (kotlin.Int) -> ??? was expected Error:(18, 23) Gradle: Type mismatch: inferred type is kotlin.reflect.KFunction2 but (kotlin.Int) -> kotlin.Boolean was expected Error:(18, 25) Gradle: Left-hand side of a callable reference with a receiver parameter cannot be empty. Please specify the type of the receiver before '::' explicitly

I'm not sure what the error is nor what type I should specify explicitly before '::'

Another question: Can I use another objects function as reference in kotlin? Something like this:

class Bar {
    fun isOdd(x: Int): Boolean = x % 2 != 0
}

class Foo {

    fun getFilteredList(){
        val bar = Bar()
        val numbers = listOf(1, 2, 3)
        numbers.filter(bar::isOdd) // Use Bar's method
    }
}
like image 488
sockeqwe Avatar asked Nov 09 '15 19:11

sockeqwe


People also ask

What is the difference between function and lambda?

The primary difference between a lambda and a regular function is that the lambda function evaluates only a single expression and yields a function object. Consequently, we can name the result of the lambda function and use it in our program as we did in the previous example.

What are we using lambdas and method reference for?

You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name.

Why method reference is better than lambda?

The method references can only be used to replace a single method of the lambda expression. A code is more clear and short if one uses a lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve the same.

What is the function of lambda function?

Lambda functions are intended as a shorthand for defining functions that can come in handy to write concise code without wasting multiple lines defining a function. They are also known as anonymous functions, since they do not have a name unless assigned one.


2 Answers

On the second example: yes, the bound function reference syntax is supported since Kotlin 1.1, so you can write bar::isOdd similarly to Java.

In the first example, the error is trying to say that isOdd is in fact a function of two parameters (of types Foo and Int), and passing a function taking two parameters as an argument whose type is function of one parameter is not allowed. To make the example compile, you can make isOdd a top-level or a local function, which would make it a function of one parameter of type Int. Or, if you use Kotlin 1.1+, use the bound function reference syntax and simply write this::isOdd.

like image 94
Alexander Udalov Avatar answered Sep 18 '22 18:09

Alexander Udalov


That's funny. "Java strikes back". Haha

Your problem is simple: you declared isOdd in class Foo, right? Then it is not a function, but a method. Which means that it requires an instance of Foo to be passed in (the this reference) - that's why it is a function of 2 parameters: Foo.(Int) -> Boolean. And the syntax error shows that - a reference to a method looks like Foo::isOdd.

Anyway, declaring a non-static method which does not use the object is an antipattern even in Java, don't you agree?

The problem might be solved by declaring a free function without a class or by making it an extension: fun Int.isOdd()

P.S. Regarding your second question - that feature is not supported yet.

like image 31
voddan Avatar answered Sep 17 '22 18:09

voddan