Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Kotlin WHEN clause for <, <=, >=, > comparisons

Tags:

kotlin

I'm trying to use the WHEN clause with a > or < comparison.

This doesn't compile. Is there a way of using the normal set of boolean operators (< <=, >= >) in a comparison to enable this?

val foo = 2  // doesn't compile when (foo) {     > 0 -> doSomethingWhenPositive()     0   -> doSomethingWhenZero()     < 0 -> doSomethingWhenNegative() } 

I tried to find an unbounded range comparison, but couldn't make this work either? Is it possible to write this as an unbounded range?

// trying to get an unbounded range - doesn't compile when (foo) {     in 1.. -> doSomethingWhenPositive()     else -> doSomethingElse() } 

You can put the whole expression in the second part, which is OK but seems like unnecessary duplication. At least it compiles and works.

when {     foo > 0 -> doSomethingWhenPositive()     foo < 0 -> doSomethingWhenNegative()     else -> doSomethingWhenZero() } 

But I'm not sure that is any simpler than the if-else alternative we have been doing for years. Something like:

if ( foo > 0 ) {     doSomethingWhenPositive() } else if (foo < 0) {     doSomethingWhenNegative() } else {     doSomethingWhenZero() } 

Of course, real world problems are more complex than the above, and the WHEN clause is attractive but doesn't work as I expect for this type of comparison.

like image 628
Jim Leask Avatar asked Jul 28 '17 15:07

Jim Leask


People also ask

What does () -> mean in Kotlin?

The -> is a separator. It is special symbol used to separate code with different purposes. It can be used to: Separate the parameters and body of a lambda expression val sum = { x: Int, y: Int -> x + y }

What is the difference between if and when in Kotlin?

when can be used either as an expression or as a statement. If it is used as an expression, the value of the first matching branch becomes the value of the overall expression. If it is used as a statement, the values of individual branches are ignored.


2 Answers

Even a flexible language such as Kotlin doesn't have a "elegant" / DRY solution for each and every case.

You can write something like:

when (foo) {     in 0 .. Int.MAX_VALUE -> doSomethingWhenPositive()     0    -> doSomethingWhenZero()     else -> doSomethingWhenNegative() } 

But then you depend on the variable type.

I believe the following form is the most idiomatic in Kotlin:

when {     foo > 0  -> doSomethingWhenPositive()     foo == 0 -> doSomethingWhenZero()     else     -> doSomethingWhenNegative() } 

Yeah... there is some (minimal) code duplication.

Some languages (Ruby?!) tried to provide an uber-elegant form for any case - but there is a tradeoff: the language becomes more complex and more difficult for a programmer to know end-to-end.

My 2 cents...

like image 180
Lior Bar-On Avatar answered Oct 19 '22 23:10

Lior Bar-On


The grammar for a when condition is as follows:

whenCondition (used by whenEntry)   : expression   : ("in" | "!in") expression   : ("is" | "!is") type   ; 

This means that you can only use is or in as special cases that do not have to be a full expression; everything else must be a normal expression. Since > 0 is not a valid expression this will not compile.

Furthermore, ranges are closed in Kotlin, so you cannot get away with trying to use an unbounded range.

Instead you should use the when statement with a full expression, as in your example:

when {     foo > 0 -> doSomethingWhenPositive()     foo < 0 -> doSomethingWhenNegative()     else -> doSomethingWhenZero() } 

Or alternatively:

when {     foo < 0 -> doSomethingWhenNegative()     foo == 0 -> doSomethingWhenZero()             foo > 0 -> doSomethingWhenPositive()         } 

which may be more readable.

like image 38
Pixel Elephant Avatar answered Oct 19 '22 23:10

Pixel Elephant