Another question: Can one override a function with...
# getting-started
j
Another question: Can one override a function with lambda expression? I was following the koans, and below code
Copy code
import java.util.*

fun getList(): List<Int> {
    val arrayList = arrayListOf(1, 5, 2)
    Collections.sort(arrayList, object : Comparator<Int> {
        override fun compare = {x: Int, y: Int -> y - x}
    })
    return arrayList
}
gave me error messages:
Copy code
Object is not abstract and does not implement abstract member public abstract fun compare(p0: Int!, p1: Int!): Int defined in java.util.Comparator
'compare' overrides nothing
Expecting '('
Can someone elaborate these messages? edit: additionally when I tried different codes in the line starting with
override fun compare
, 1.
Copy code
override fun compare(x: Int, y: Int) {
            return y - x
        }
this did not work as well, producing error messages
Copy code
Return type of 'compare' is not a subtype of the return type of the overridden member 'public abstract fun compare(p0: Int!, p1: Int!): Int defined in java.util.Comparator'
Type mismatch: inferred type is Int but Unit was expected
I don’t understand the error message. Why was the expected type
Unit
, not
Int
? Shouldn’t the compiler expect the return type as
Int
? BUT 2. with a slight modification,
Copy code
override fun compare(x: Int, y: Int): Int {
            return y - x
        }
this worked. 3.
Copy code
override fun compare(x: Int, y: Int) = y - x
This works also. But in this case, I also didn’t explicitly write the return type, same as approach 1. What are the differences between them? Why did 1. produce error while the other two didn’t? What’s happening under the hood?
k
Your
compare
declaration is syntactically incorrect - it is a function, but it does not have parentheses for arguments and they are required for function declaration - that is what
Expecting '('
error is about. You need a proper function declaration with a matching signature to provide the implementation for interface method and compiler cannot find such function in your object - that's why it throws
Object is not abstract and does not implement abstract member
And no, you can't override a function with a lambda expression. If you declare a lambda in a class, it essentially is a property of a functional type, and as such can only override a property of the same type, not a function. The syntax for the functional property declaration will be the following (note that there is no
fun
here):
Copy code
val compare = { x: Int, y: Int -> y - x }
👍 2
As for your first attempt to fix - see "Explicit return types" section in https://kotlinlang.org/docs/reference/functions.html. Basically, you need to explicitly provide return type for a function with body enclosed in
{}
, otherwise compiler assumes the function returns
Unit
. Return type inference works only for single-expression functions.
👍 1
Also note that
Comparator
is a functional interface, therefore you can replace anonymous object declaration with a lambda expression for its only abstract method implementation and the compiler will create anonymous object under the hood for you:
Copy code
Collections.sort(arrayList) { x, y -> y - x }
👍 1
j
Thanks for the explanations! Yes, I noticed that a
Comparator
is a functional interface in the next koan link https://play.kotlinlang.org/koans/Introduction/SAM%20conversions/Task.kt But then here why does one not need to explicitly state the types of
x
,
y
, and also the return type, whereas in cases above I had to?
k
Because you are declaring a function in cases above, and functions in Kotlin have no type inference for parameters - all parameters types have to be specified explicitly. And in the latter case you are dealing with lambda, and for lambdas the compiler can infer types of their parameters from the context.
j
Oh I see.. Thanks a lot again for the clarification.