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
}
}
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.
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.
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.
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.
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With