Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between lambda and normal Kotlin function?

I'm trying to learn some Android basics, and have this UI to generate random number on click:

@Composable
fun DiceWithButton(modifier: Modifier = Modifier) {
    var value by remember { mutableStateOf(1) }
    fun rollNew() {
        value = (1..6).random()
    }
    Column(modifier = blabla) {
        Text(text = value.toString())
        Button(onClick = rollNew) {
            Text("Roll")
        }
    }
}

It fails to build with message Type mismatch: inferred type is Unit but () -> Unit was expected

But when I rewrite rollNew as lambda, it works fine:

var rollNew = {
    value = (1..6).random()
}

This is confusing for me coming from the Python/Javascript/Golang background, where any function value is equally callable with ().

What is the difference in Kotlin? Why rollNew has Unit type when defined with fun? Or did Kotlin tries to call rollNew when it's function, therefore Unit?

like image 552
Bunyk Avatar asked Jul 01 '26 23:07

Bunyk


1 Answers

To use a function declared by a function declaration as a value of a function type, you should use a callable reference expression, i.e.

Button(onClick = ::rollNew)

Just writing the name of the function on its own, is invalid syntax.

This is confusing for me coming from the Python/Javascript/Golang background, where any function value is equally callable with ().

In Kotlin, rollNew is not a "function value". It is a name declared by a function declaration, not an expression on its own. ::rollNew is a function value, as well as lambda expressions and anonymous function declarations (these two are collectively called function literals).

What is the difference in Kotlin? Why rollNew has Unit type when defined with fun? Or did Kotlin tries to call rollNew when it's function, therefore Unit?

rollNew on its own is not an expression at all, so talking about its type is nonsense. As you guessed, this is just the compiler "guessing" that you want to call it. In addition to the incomparable types error message, you also get a "Function invocation rowNew() expected" error.

Ah, so in Kotlin functions are not first-class citizens, but lambas are, and :: is used to convert function to lambda?

This is conflating syntax and semantics. Lambda expressions and callable references are both syntactic features of the language. Semantically, these both represent the idea of "functions" - the type of these expressions are function types, among other things. Being able to pass "functions" around and call them is what makes functions a first-class citizen, regardless of the syntax you use to do this. And of course, :: doesn't convert anything to lambdas. This is totally different from the syntax of a lambda expression.

As an analogy, this is like seeing that val str = Foo produces an error, but val str = "Foo" compiles, and concludes that "strings are not first class citizens, but string literals are".

That said, generic functions (functions with free type parameters) are indeed not first-class citizens though, but that's another story.

like image 199
Sweeper Avatar answered Jul 04 '26 10:07

Sweeper