I want to create a lambda and assign it to a variable and the following works as expected:
val rollDice = { min: Int, max: Int -> (min..max).random() }
However, when I tried to assign default values to the parameters I got an error:
val rollDice = { min: Int = 1, max: Int = 12 -> (min..max).random() }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unexpected tokens (use ';' to separate expressions on the same line)
Is it not possible to assign default values to parameters in lambda expressions in Kotlin?
TLDR: Lambda expressions cannot have default parameters. If you need them, you should declare a function (can be locally inside another function).
To elaborate, let's look at different ways how function-like types can be defined in Kotlin. Intuitively, one would expect them to work the same, but there are subtle discrepancies in their functionality.
1. Overloaded functions
When defining function overloads manually (the Java way), it's possible to not just call the function with any allowed argument number, but also store the function reference in a type using any argument number.
2. Functions with default parameters
More idiomatic in Kotlin is the use of default parameters. While this seems to be mostly equivalent to overloaded functions, it's not. The notable difference is: only a single function is declared, and type inference will consider different argument counts only when calling the function, but not when storing it via function reference.
3. Anonymous functions
Anonymous functions allow no default parameters even in the declaration, so there's only one way of calling them. Furthermore, the variable storing them is of function type, which loses information about the parameter names and thus prevents a call with named arguments.
4. Lambda expressions
Like anonymous functions, lambda expressions allow no default parameters and cannot be called with named arguments. Since they are stored immediately as a function type like
(Int, Int) -> Int
, they undergo the same restrictions as function types referring to actual functions.Type inference only works if the parameter types are specified either in the lambda expression, or in the function type to assign to:
The main takeaway here is that these 4 callables, while supporting the same basic functionality, differ in the following points:
By referring to the callables as function types (which is the only option for anonymous functions and lambdas), you lose information that's present in the original declaration.