Kotlin. Lambda vs Function reference

Kotlin has long been the mainstream programming language on Android. One of the reasons why I like this language is that the functions in it are first class objects . That is, a function can be passed as a parameter, used as a return value, and assigned to a variable. Also, instead of a function, you can pass a so-called lambda . And recently I had an interesting problem related to replacing the lambda with a function reference.





Imagine that we have a class Button



that receives a function in the constructor as a parameteronClick







class Button(
    private val onClick: () -> Unit
) {
    fun performClick() = onClick()
}
      
      



And there is a class ButtonClickListener



that implements the logic of button clicks





class ButtonClickListener {
    fun onClick() {
        print(" ")
    }
}
      
      



In the class ScreenView



, we store a variable lateinit var listener: ButtonClickListener



and create a button, which is passed a lambda, inside which the method is calledButtonClickListener.onClick







class ScreenView {
    lateinit var listener: ButtonClickListener
    val button = Button { listener.onClick() }
}
      
      



In the method, main



we create an object ScreenView



, initialize the variable listener



and simulate clicking on the button





fun main() {
    val screenView = ScreenView()
    screenView.listener = ButtonClickListener()
    screenView.button.performClick()
}
      
      



After starting the application, everything works out fine and the line "Button pressed" is displayed.





ScreenView



, - val button = Button { listener.onClick() }



. , ButtonClickListener.onClick



onClick: () -> Unit



, , , .





class ScreenView {
    lateinit var listener: ButtonClickListener
    val button = Button(listener::onClick)
}
      
      



- listener





Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property listener has not been initialized
at lambdas.ScreenView.<init>(ScreenView.kt:6)
at lambdas.ScreenViewKt.main(ScreenView.kt:10)
at lambdas.ScreenViewKt.main(ScreenView.kt)
      
      



, Java . .





Function0



invoke



, . - listener.onClick()







private final Button button = new Button((Function0)(new Function0() {
    public final void invoke() {
       ScreenView.this.getListener().onClick();
    }
}));
      
      



, listener



.





. Function0



, invoke()



, , onClick



this.receiver



. receiver



Function0



listener



, listener



lateinit



, receiver



- listener



null



, . .





Button var10001 = new Button;
Function0 var10003 = new Function0() {
   public final void invoke() {
      ((ButtonClickListener)this.receiver).onClick();
   }
};
ButtonClickListener var10005 = this.listener;
if (var10005 == null) {
   Intrinsics.throwUninitializedPropertyAccessException("listener");
}

var10003.<init>(var10005);
var10001.<init>((Function0)var10003);
this.button = var10001;
      
      



That is, the difference between a lambda and a function reference is that when a function reference is passed, the variable whose method we are referring to is fixed at creation, and not at execution, as happens when a lambda is passed.





This leads to the following interesting problem: What will be printed after the program starts?





class Button(
    private val onClick: () -> Unit
) {
    fun performClick() = onClick()
}

class ButtonClickListener(
    private val name: String
) {
    fun onClick() {
        print(name)
    }
}

class ScreenView {
    var listener = ButtonClickListener("First")
    val buttonLambda = Button { listener.onClick() }
    val buttonReference = Button(listener::onClick)
}

fun main() {
    val screenView = ScreenView()
    screenView.listener = ButtonClickListener("Second")
    screenView.buttonLambda.performClick()
    screenView.buttonReference.performClick()
}
      
      



  1. FirstFirst







  2. FirstSecond







  3. SecondFirst







  4. SecondSecond







Answer

3





Thanks for reading, I hope someone was interested and useful!








All Articles