vsnyc vsnyc - 1 month ago 7
Scala Question

What does "double right-arrow Type" with no LHS mean in function argument

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
.

Answer

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 Ints, the 2nd of which is evaluated lazily."

Comments