Reputation: 2257
I am having trouble interpreting "double-rightarrow Type" specified as a function argument without a LHS (left hand side) e.g. () => Int
is from ()
to Int
but what does just => Int
mean?
e.g. see the first argument of foo
method below, what is the type of f
? Is it (Int, () => Int) => Int
?
For the definition of bar
, where y is passed by name, I've interpreted it as a function with no argument that will produce an Int, which looks equivalent to definition of baz
.
I could try to reason that f
in foo
takes the second argument as call by name, and is not from () => Int
but that is contradicting that fact that bar
and baz
definitions are identical in javap. What am I missing?
object ParamTest {
def foo(f: (Int, => Int) => Int, x: Int) : Int = 10
def bar(x: Int, y: => Int) : Int = 20
def baz(x: Int, f: () => Int) : Int = 30
def qux(f: (Int, () => Int) => Int, x: Int) : Int = 40
}
For testing I compiled the above class with scalac ParamTest.scala
javap ParamTest
gives me:
public final class ParamTest {
public static int qux(scala.Function2<java.lang.Object, scala.Function0<java.lang.Object>, java.lang.Object>, int);
public static int baz(int, scala.Function0<java.lang.Object>);
public static int bar(int, scala.Function0<java.lang.Object>);
public static int foo(scala.Function2<java.lang.Object, scala.Function0<java.lang.Object>, java.lang.Object>, int);
}
That seems to indicate that foo and qux have the same method signature. In other words, I could interpret => Int
as () => Int
, but
foo(baz,100)
gives me a type mismatch error
scala> import ParamTest._
import ParamTest._
scala> foo(bar,100)
res0: Int = 10
scala> foo(baz,100)
<console>:11: error: type mismatch;
found : (Int, () => Int) => Int
required: (Int, => Int) => Int
foo(baz,100)
^
EDIT: This is not the same as this question. I'm not asking the practical difference between call-by-name: => Type
and () => Type
. What I'm more interesting in knowing is the internals. How does scala differentiate between the two, when javap or cfr decompilation gives me identical definitions for foo
and qux
; and for bar
and baz
.
Upvotes: 5
Views: 537
Reputation: 51271
As you've discovered, () => A
and => A
are not the same thing.
Call by name (i.e. => A
) simply means: "delay the evaluation of this method argument." In other words, lazy evaluation.
def f(x: Int, y: => Int) = ???
f(3+5, 2+4)
In this example the addition of 3+5 is done at the call site and the x
value is 8. The addition of 2+4, on the other hand, isn't done until y
is referenced inside the body of the method f()
. If that reference is in an if...else...
branch that doesn't get executed then the addition is never done.
This is pretty pointless for simple evaluations like Int
addition, but it becomes more meaningful if the argument is an expensive evaluation, of if it's a block of code with side effects.
So, in answer to your question, the meaning of f: (Int, => Int) => Int
is: "f
takes two arguments and produces an Int
, the arguments are 2 Int
s, the 2nd of which is evaluated lazily."
Upvotes: 6