How are functions inside functions translated?


#1

Hi Kotlin Community.

I have stumbled upon this syntax, defining a function inside a function, a few days ago and I have a few questions on it.

like so

fun setupUI(score: Int) {
    fun getProperColor() = if (score > 0) Color.GREEN else Color.RED
    
    ui.text.textColor = getProperColor()
    ui.text.onClick {  ui.someOtherText.textColor = getProperColor() }
}
  1. What is the equivalent to this in Java.
  2. I am trying to increase extensibility here ( if the business for color changes, i change the function and it would work for all texts) . Does it impact performace or memory in any way ?

Thanks in advance


#2

Java equivalent:

  void setupUI(int score) {
    Supplier<Color> getProperColor = () -> score > 0 ? Color.GREEN : Color.RED;

    ui.text.textColor = getProperColor.get()
    ui.text.onClick(() -> ui.someOtherText.textColor = getProperColor.get());
  }

#3

So it basically generates an instance of an interface ?


#4

From what I can tell, it generates a class implementing the proper interface from kotlin/jvm/functions. So in this case, it would be Function0.


#5

If that is true, therefore copy pasting the code can be faster for the system


#6

Nope! Wrong!

fun function1() {
    fun function2() {

    }
    function2()
}

compiles to

public final class TestKt {

  public final static function1()V
   L0
    LINENUMBER 4 L0
    GETSTATIC TestKt$function1$1.INSTANCE : LTestKt$function1$1;
    ASTORE 0
   L1
    LINENUMBER 7 L1
    ALOAD 0
    CHECKCAST TestKt$function1$1
    INVOKEVIRTUAL TestKt$function1$1.invoke ()V
   L2
    LINENUMBER 8 L2
    RETURN
   L3
    LOCALVARIABLE function2$ LTestKt$function1$1; L1 L3 0
    MAXSTACK = 1
    MAXLOCALS = 1

  final static INNERCLASS TestKt$function1$1 null null
}

final class TestKt$function1$1 extends kotlin/jvm/internal/Lambda  implements kotlin/jvm/functions/Function0  {

  public synthetic bridge invoke()Ljava/lang/Object;
    ALOAD 0
    INVOKEVIRTUAL TestKt$function1$1.invoke ()V
    GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
    ARETURN
    MAXSTACK = 1
    MAXLOCALS = 1

  public final invoke()V
   L0
    LINENUMBER 6 L0
    RETURN
   L1
    LOCALVARIABLE this LTestKt$function1$1; L0 L1 0
    MAXSTACK = 0
    MAXLOCALS = 1

  <init>()V
    ALOAD 0
    ICONST_0
    INVOKESPECIAL kotlin/jvm/internal/Lambda.<init> (I)V
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 1

  public final static LTestKt$function1$1; INSTANCE

  static <clinit>()V
    NEW TestKt$function1$1
    DUP
    INVOKESPECIAL TestKt$function1$1.<init> ()V
    PUTSTATIC TestKt$function1$1.INSTANCE : LTestKt$function1$1;
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 0

  OUTERCLASS TestKt function1 ()V
  final static INNERCLASS TestKt$function1$1 null null
}

What does this mean? The Kotlin compiler generates a singleton class which implements the Function interface. The compiler DOES NOT generate a new instance of the function every time the parent function is called.

Exactly - But it’s a singleton class with only one instance.