Home > Software engineering >  When is it a block and when is it a lambda?
When is it a block and when is it a lambda?

Time:10-07

How does the Kotlin compiler decide whether an expression enclosed in { } is a block or a lambda?

Consider this:

val a: Int
if (cond)
    a = 1
else
    a = 2

can be written more succinctly as:

val a =
    if (cond)
        1
    else
        2

Similarly, one might think that this:

val a: () -> Int
if (cond)
    a = { 1 }
else
    a = { 2 }

should be able to be written more succinctly like this:

val a =
    if (cond)
        { 1 }
    else
        { 2 }

But this is not the same: a is now an Int, and not of type () -> Int, because now the { 1 } is no longer a lambda. What are the rules that say whether something is a lambda or a block?

CodePudding user response:

I didn't look into the Kotlin lexer, but I guess there are few possible places in the code where the compiler expects either a single expression or a block of code. That includes the code immediately following most of control flow statements like: if, else, while, when (one of its cases), etc. If you put { in one of these places, it will be interpreted as a start of the block of code related to this control flow statement and not as a lambda.

This is as simple as that. Note that even if you hint the compiler about the type, it still won't work:

// compile error
val a: () -> Int = if (cond)
    { 1 }
else
    { 2 }

It will be interpreted more like this:

// compile error
val a: () -> Int = if (cond) {
    1
} else {
    2
}

{ after if condition is always interpreted as a start of block of code. You need to put double {, } in cases like this:

// works fine
val a: () -> Int = if (cond) {
    { 1 }
} else {
    { 2 }
}

CodePudding user response:

To put it very succinctly and easy to remember, the first opening brace after an if/when/else/for is always assumed to be the opening of a block. Use double braces if you want a lambda in there.

  • Related