https://kotlinlang.org logo
Title
j

JP

02/23/2020, 5:35 AM
Another question: Can one override a function with lambda expression? I was following the koans, and below 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:
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.
override fun compare(x: Int, y: Int) {
            return y - x
        }
this did not work as well, producing error messages
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,
override fun compare(x: Int, y: Int): Int {
            return y - x
        }
this worked. 3.
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

Kiryushin Andrey

02/23/2020, 7:10 AM
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):
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:
Collections.sort(arrayList) { x, y -> y - x }
👍 1
j

JP

02/23/2020, 7:21 AM
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

Kiryushin Andrey

02/23/2020, 7:25 AM
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

JP

02/23/2020, 7:27 AM
Oh I see.. Thanks a lot again for the clarification.