vsnyc
vsnyc

Reputation: 2257

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.

Upvotes: 5

Views: 537

Answers (1)

jwvh
jwvh

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

Upvotes: 6

Related Questions