Libathos
Libathos

Reputation: 3362

Kotlin function syntax

I'm doing the Kotlin Koans tests in order to familiarise myself with Kotlin. In a certain test I have to override the compareTo method. In the first case everything work as intended

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {

    operator fun compareTo(other: MyDate)= when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }

}

Now in the second case where I'm writing the compareTo a little bit differently I get a ton of compilation errors.

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {


     operator fun compareTo(other: MyDate){

        when {
            year != other.year -> return year - other.year
            month != other.month -> return month - other.month
            else -> return dayOfMonth - other.dayOfMonth
       }
     }


 }

First of all, at the operator keyword, I get an error:

'operator' modifier is inapplicable on this function: must return Int

and in the returns I get

Type mismatch: inferred type is Int but Unit was expected

I cannot understand why these errors occur since the first implementation returns the same Ints

Upvotes: 1

Views: 2240

Answers (3)

guenhter
guenhter

Reputation: 12177

Just an addition to @Mibac's answer: You can make this a little bit shorter:

operator fun compareTo(other: MyDate) = when {
    year != other.year -> year - other.year
    month != other.month -> month - other.month
    else -> dayOfMonth - other.dayOfMonth
}

Upvotes: 0

Mibac
Mibac

Reputation: 9488

That's because = works as { return X }This applies only to function definitions. So this means that in the first example your code is equal to this

operator fun compareTo(other: MyDate):Int {
    return when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }
}

But in your 2nd example you don't return the result of the when. That results in the compiler being confused because it expected you to return a Int but you return Unit instead (equivalent of Java's void)

So all you need to do is to add an explicit return type (Int in this case) to it (fun X(/*args*/): Int or other applicable type)

Upvotes: 3

BakaWaii
BakaWaii

Reputation: 6992

In your first example, the return type of compareTo(MyDate) is inferred as Int because all branch of the when expression return an Int.

In your second example, the return type of compareTo(MyDate) is Unit. Since you function has the block body, so the return type must be specified explicitly (unless it's intended for them to return Unit). So, Unit is expected here for the return type, but the return type inferred from your when expression is Int. That's why you get the error:

Type mismatch: inferred type is Int but Unit was expected

Here is the official explanation for explicitly defining the return type of functions with block bodies:

Functions with block body must always specify return types explicitly, unless it's intended for them to return Unit, in which case it is optional. Kotlin does not infer return types for functions with block bodies because such functions may have complex control flow in the body, and the return type will be non-obvious to the reader (and sometimes even for the compiler).

So, the correct way to declare compareTo(MyDate) is to specify the return type of the function if it includes the block body:

operator fun compareTo(other: MyDate): Int {
    when {
        year != other.year -> return year - other.year
        month != other.month -> return month - other.month
        else -> return dayOfMonth - other.dayOfMonth
    }
}

This solves another error at the same time since the comparison operator is required to return an Int.

Upvotes: 2

Related Questions