I'm a little bit confused about using call-by-name parameters in Scala. Please help me to understand what is going on here. Consider the following example of using call-by-name parameter:
def param = {println("Param evaluates"); 40}
def lazyEval(x: => Int) = {
println("lazy");
x
}
val s = lazyEval(param + 2)
// s = 42
I have several question related to each other about this:
lazyEval
method expects parameter of type => Int
, so why param + 2
operation is legal? Why we can add integer 2 to object with type => Int
(im my understanding under the hood it is <function0>
) when calling lazyEval
method? As IDE hints me, the lazyEval
function expects parameter of type Int
instead of => Int
(what the hell?).
Why after changing callback type from => Int
to () => Int
code doesn't compile? Is this 2 types are different? I though the short version ('=> Int') is just a syntactical sugar.
After some playing with code, I finally could change code so it will compile with () => Int
. This way is more intuitive for me.
.
def param = {println("Param evaluates"); 40}
def lazyEval(x: () => Int) = { // changed type to '() => Int'
println("lazy");
x() // explicitly calling function using parentheses '()'
}
val s = lazyEval(param _) // adding underscore after method name and removing `+2`
What is differences between this version and first one (with callback => Int
type)? Why in this version we can't make addition of integer with value 2
and the param
function (I mean thislazyEval(param _ + 2)
)? And what mean underscore after method name? (I guess it used to pass method itself, not it return value)
Thanks in help
so why param + 2 operation is legal? Why we can add integer 2 to object with type => Int
We can add 2
to param
because it evaluates to Int
, you're adding Int
with Int
. param
isn't a function => Int
, it is a method, so param + 2
is => Int
. ie. an expression that evaluates to Int
.
Why after changing callback type from => Int to () => Intcode doesn't compile? Is this 2 types are different? I though the short version ('=> Int') is just a syntactical sugar.
=> Int
and () => Int
don't mean the same thing. One is anything that evaluates to Int
, and the other a function from Unit
to Int
. 2
isn't a () => Int
, but () => 2
is. Or you could also say 2
is => Int
.
Why in this version we can't make addition of integer with value 2 and the param function (I mean thislazyEval(param _ + 2))? And what mean underscore after method name? (I guess it used to pass method itself, not it return value)
param
is a method, not a function. The underscore in this case lifts param
into a function. So param _
is a function () => Int
. And that's exactly why we can't add 2
to it, because you can't add 2
to a function. Basically the exact reason why you think (1) shouldn't work.
In summary:
def lazyEval(x: => Int)
is a method with a parameter x
that can be anything that evaluates to Int
. That could be any method that returns Int
, a concrete value of Int
, or some block of code that resolves to Int
, etc.
lazyEval(x: () => Int)
is a method with a parameter x
that can only be a parameterless function that returns Int
. That could mean the method param
lifted to a function, or something weird like () => 2
. But it must be a function. So simply passing a value like 2
cannot work.