Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin using when for simple conditions

I personaly like the when syntax as it causes identation to be much clearer. However I am concerned about the 'penalties' that I might be introducing by doing this.

I'm not really an expert on bytecode, but I can see that for the same 'logic', the when clause takes more bytecode operations.

Simple file with 3 different Kotlin functions

package com.whatever

fun method1(): String {
  return if (BuildConfig.DEBUG) "something" else "else"
}

fun method2(): String {
  return if (BuildConfig.DEBUG) {
    "something"
  } else {
    "else"
  }
}

fun method3(): String {
  return when (BuildConfig.DEBUG) {
    true -> "something"
    else -> "else"
  }
}

Generated bytecode

  // access flags 0x19
  public final static method1()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 4 L0
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z
    IFEQ L1
    LDC "something"
    GOTO L2
   L1
    LDC "else"
   L2
    ARETURN
   L3
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x19
  public final static method2()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 8 L0
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z
    IFEQ L1
   L2
    LINENUMBER 9 L2
    LDC "something"
   L3
    GOTO L4
   L1
    LINENUMBER 11 L1
    LDC "else"
   L5
    LINENUMBER 8 L5
   L4
    ARETURN
   L6
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x19
  public final static method3()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 16 L0
    GETSTATIC com/whatever/BuildConfig.DEBUG : Z
    ISTORE 0
   L1
    LINENUMBER 17 L1
    ILOAD 0
    ICONST_1
    IF_ICMPNE L2
   L3
    LDC "something"
    GOTO L4
   L2
    LINENUMBER 18 L2
    LDC "else"
   L5
    LINENUMBER 16 L5
   L4
    ARETURN
   L6
    MAXSTACK = 2
    MAXLOCALS = 1

Can someone point out how significant this cost is? And wether we should try to stay away from this pattern for simple operations?

Thanks

like image 370
Robert Estivill Avatar asked Oct 24 '17 12:10

Robert Estivill


People also ask

How do you use if condition in Kotlin?

Kotlin has the following conditionals: Use if to specify a block of code to be executed, if a specified condition is true. Use else to specify a block of code to be executed, if the same condition is false. Use else if to specify a new condition to test, if the first condition is false.

How do you write when in Kotlin?

For example, fun main(args: Array<String>) { val n = -1 when (n) { 1, 2, 3 -> println("n is a positive integer less than 4.") 0 -> println("n is zero") -1, -2 -> println("n is a negative integer greater than 3.") } } When you run the program, the output will be: n is a negative integer greater than 3.

How do I choose between switches and when in Kotlin?

Kotlin does not provide any option to write a switch-case statement. However, Kotlin provides an option to implement when() which works exactly the same way switch works in other programming languages.

What is the best alternative of switch-case in Kotlin?

Kotlin does not provide an option to write a switch-case statement; however we can implement the switch-case functionality in Kotlin using the when() function which works exactly the same way switch works in other programming languages.


1 Answers

The only difference here is that in method3 the BuildConfig.DEBUG value gets stored in a local variable first. When decompiling the bytecode to Java, you see the following:

   @NotNull
   public static final String method2() {
      return BuildConfig.DEBUG?"something":"else";
   }

   @NotNull
   public static final String method3() {
      boolean var0 = BuildConfig.DEBUG;
      return var0?"something":"else";
   }

This is negligible.


If we expand the if/else clauses, we can construct the following:

fun method4(a: Int): String {
    if (a == 1) {
        return "1"
    } else if (a == 2) {
        return "2"
    } else if (a == 3) {
        return "3"
    } else {
        return "4"
    }
}

fun method5(a: Int): String {
    when (a) {
        1 -> return "1"
        2 -> return "2"
        3 -> return "3"
        else -> return "4"
    }
}

The decompiled bytecode for this is:

@NotNull
public static final String method4(int a) {
  return a == 1?"1":(a == 2?"2":(a == 3?"3":"4"));
}

@NotNull
public static final String method5(int a) {
  switch(a) {
  case 1:
     return "1";
  case 2:
     return "2";
  case 3:
     return "3";
  default:
     return "4";
  }
}

Thus, a simple when statement boils down to a switch statement in Java. See 'Why switch is faster than if' for a comparison between these two.

like image 55
nhaarman Avatar answered Feb 20 '23 14:02

nhaarman