Dusko
Dusko

Reputation: 650

What is the right approach when Kotlin function does not take nullable type

So I was solving Koans problem and through my overly complex solution bumped into a thing that bothers me. I was using Int.compareTo() function on nullable types. It is "easy" if the first one is nullable because I just write:

val a : Int? = 1
val b : Int = 1
a?.compareTo(b)

But if b is nullable, then I was not able to get it to work, maybe I missed something somewhere? So what to do when this is the case?

val a : Int? = 1
val b : Int? = 2
a?.compareTo(b)

I get a syntax error saying "None of the following functions can be called with the arguments supplied."

But, when I introduce this:

val a : Int? = 1
val b : Int? = 2
val x : Int = b ?: 0;
o1?.compareTo(x)

It works but it feels like it is not the right way to do this. Is there a better way?

Upvotes: 2

Views: 189

Answers (5)

Vadims Savjolovs
Vadims Savjolovs

Reputation: 2668

You can do

val a: Int? = 1
val b: Int? = 2
b?.let {
   a?.compareTo(b)
}

let block will be executed only if b is not null.

Or just

if (a != null && b != null) {
   a.compareTo(b)
}

I think second solution is very clear and easy to read.

Upvotes: 2

holi-java
holi-java

Reputation: 30686

the expression should be like this:

val result = b?.let { a?.compareTo(b) ?: -1 } ?: 1;

Examples

> a = 1      b = 2          --->  -1

> a = null   b = 2          --->  -1

> a = null   b = -1          --->  -1

> a = 1      b = null       --->   1

> a = -1      b = null       --->   1

> a = null   b = null       --->   1 // the order is no matter

IF you want to let null compare null return 0 then the expression is a bit long:

val result = b?.let { a?.compareTo(b) ?: -1 } ?: a?.let { 1 } ?: 0;

Note: you don't care about the performance, since let function is an inline function. which means it will generates the code like as below in java:

int result =  b != null ? a != null ? a.compareTo(b) : -1 : a != null ? 1 : 0;

Upvotes: -1

Mibac
Mibac

Reputation: 9448

The only better way is to implement compareTo yourself. The default compare does not know what result you want when you compare i.e. 12 to null or null to null. It only knows how to compare actual numbers. I think your best way is to implement the behaviour you want for dealing with nulls.

Example implementation:

fun main(args: Array<String>) {
    println(compareNullableInts(null, 2))    // -1
    println(compareNullableInts(null, null)) // 0
    println(compareNullableInts(2, null))    // 1
    println(compareNullableInts(10, 5))      // 1
}


fun compareNullableInts(a: Int?, b: Int?): Int {
    if (a == null && b == null) return 0
    if (a == null) return -1
    if (b == null) return 1
    return a.compareTo(b)
}

Upvotes: 0

tynn
tynn

Reputation: 39843

You should try to implement your solution without nullability. But if you still need it and if it's safe to assume that null==0 you should not use the ?. method call. It'll return you an Int? as well. Just map both null integers to 0.

(a?:0).compareTo(b?:0)

Upvotes: 0

Plog
Plog

Reputation: 9622

The Int.compareTo() method's signature is not defined for nullable arguments so it's not possible to do without ensuring null safety of the argument by e.g. using an elvis operator just as you have suggested.

Upvotes: 0

Related Questions