2

Say, first, I have this function:

def number5()={
      println("number 5 starting")
      println("number 5 exiting")
      5
}

And then:

def giveMeCallByNameParameter(f: =>Int)={
      println("starting")
      f
      println("exiting")
}

When I call it:

giveMeCallByNameParameter(number5)

I get this result:

starting
number 5 starting
number 5 exiting
exiting

And if I also have this function:

def giveMeAnotherFunction(f: ()=>Int)={
      println("starting")
      f()
      println("exiting")
}

And I call it:

giveMeAnotherFunction(number5)

I get the same result:

starting
number 5 starting
number 5 exiting
exiting

So, are they different at all? Other than the difference of having or not having the parenthesis?

If they are not different? Then why do we have this terminology call by name?

Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87
  • Note: those are methods, not functions. In fact, one of the differences between by-name parameters and parameters which are functions is that functions cannot have by-name parameters, only methods can. – Jörg W Mittag Sep 24 '14 at 16:17

4 Answers4

3

By-name parameters can be any valid expression. Functions are also valid expressions, but just one kind of expression.

The big difference between by-name parameters and by-value parameters is that by-value parameters, the most common kind of function parameter, are evaluated before being passed into the function. By-name parameters' evaluation is delayed until at least after being passed into the function. The function itself may or may not evaluate the parameter, it is not obligated to.

It just so happens that functions have this same kind of property, but again, as I said earlier, functions are just one kind of expression, whereas by-name parameters can take any kind of valid expression.

A great use case for a by-name parameters is in building a custom assert function:

def byNameAssert(predicate: => Boolean) =
  if (assertionsEnabled && !predicate)
    throw new AssertionError

This way, you could turn off the evaluation of asserted conditions by controlling the assertionsEnabled value.

If assertions aren't enabled, you could even have an expression, which would ordinarily throw, not yield an exception:

byNameAssert(x / 0 == 0)

Also note well that the expression, x / 0 == 0, is not a function! By-name parameters can take any kind of expression but will defer their evaluation until at least after the function is called.

Hope this helps!

Daniel Miladinov
  • 1,582
  • 9
  • 20
2

In this particular example both looks the same. But consider this use case

giveMeCallByNameParameter(number5 * number5)

You get this result:

starting
number 5 starting
number 5 exiting
number 5 starting
number 5 exiting
exiting

If you tried to do the same on giveMeAnotherFunction, it won't compile

scala> giveMeAnotherFunction(number5() * number5())
:10: error: type mismatch;
found : Int
required: () => Int
giveMeAnotherFunction(number5() * number5())

You must send a function not just any expression

giveMeAnotherFunction(() => number5 * number5)
tabdulradi
  • 7,456
  • 1
  • 22
  • 32
1

No difference as far as I know, at least in your example.

Incerteza
  • 32,326
  • 47
  • 154
  • 261
0

There is a difference.

  • call by name is only evaluated when you use it, also it expect a Value
  • Function, on the other hand, is a mapping not a Value

Thus, so you change method number5 to a function, you can not use call by name, but you can use in function

def number5()={
  println("number 5 starting")
  println("number 5 exiting")
  5
}

def func: () => Int = number5 // change method to function

def giveMeCallByNameParameter(f: =>Int)={
  println("starting")
  f
  println("exiting")
}

giveMeCallByNameParameter(func) //compilation error

def giveMeAnotherFunction(f: ()=>Int)={
  println("starting")
  f()
  println("exiting")
}

giveMeAnotherFunction(func) // this is fine

Also, the reason you can use method in the giveMeAnotherFunction which needs a function, is because ETA-expansion. There is a lot of examples using it like map, foldLeft and so on.

Xiaohe Dong
  • 4,953
  • 6
  • 24
  • 53