max
max

Reputation: 52235

Call by value with values interpreted as zero-argument functions vs call by name

In this comment, @Ben suggested that call by name is equivalent to call by value where values are zero-argument functions. If I understood correctly,

def callByName(x: => Int) = {
  // some code
}
callByName(something())

is equivalent to

def callByValue(x: () => Int) = {
  // same code as above, but all occurrences of x replaced with x()
}
callByValue(()=>something())

(Edit: I fixed mistake in signature as pointed out by @MichaelZajac, @LukaJacobowitz: originally, it said callByValue(x: Int).)

In other words, the whole "call by name" concept is just syntactic sugar: everything it does can be achieved (with a few extra keystrokes) using "call by value". If true, it makes it very easy to understand call by name; in fact, I've used this technique in python (python has first-class functions).

However, further down in the comments, the discussion became somewhat more confusing, and I was left with the feeling that it's not quite so simple.

So is there something more substantive to "call by name"? Or is it just an automatic creation of zero-argument functions by the compiler?

Upvotes: 0

Views: 56

Answers (2)

Luka Jacobowitz
Luka Jacobowitz

Reputation: 23502

I'm assuming you meant your callByValue function to take a () => Int instead of just an Int as otherwise it wouldn't make a lot of sense.

It's pretty much exactly what you think. The compiler generates a Function0 instance. You can see this pretty nicely when you decompile Scala code with Javap.

Another thing of note is, that the generated Function0 will be reevaluated every time you use the by-name parameter inside your function, so if you only want it to be computed once you'll want to do something like this:

def callByName(x: => Int) = {
   val a = x
   // do something with a here
}

Here is some more information on the whole concept. Also you can see how Scala compiles by-name parameters quite neatly in this question:

def getX[T <: X](constr: ⇒ T): Unit = {
    constr
}

decompiled in Java is equivalent to:

public <T extends X> void getX(Function0<T> constr) {
    constr.apply();
}

Upvotes: 1

Michael Zajac
Michael Zajac

Reputation: 55569

Yes, but your example isn't quite right. The signature of callByValue, as written in your question, will evaluate x before callByValue is invoked.

The following would be roughly equivalent to a call-by-name:

def callByValue(x: () => Int) = {
  // same code as above, but all occurrences of x replaced with x()
}

The distinction is important, because your version of callByValue would only accept Ints, not functions that return Ints. It also wouldn't compile if you followed the procedure of replacing x with x().

But yes, a call-by-name parameter of => A is roughly equivalent to () => A, except that the former is simply more convenient to use. I say roughly because they are different types, and their applications are slightly different. You can specify () => A to be the type of something, but not => A. And of course with x: () => A, you must manually call x() instead of x.

Upvotes: 1

Related Questions