Call by name vs call by value in Scala, clarificat

2019-01-01 03:01发布

As I understand it, in Scala, a function may be called either

  • by-value or
  • by-name

For example, given the following declarations, do we know how the function will be called?

Declaration:

def  f (x:Int, y:Int) = x;

Call

f (1,2)
f (23+55,5)
f (12+3, 44*11)

What are the rules please?

标签: scala
16条回答
宁负流年不负卿
2楼-- · 2019-01-01 03:29

In the case of your example all the parameters will be evaluated before it's called in the function , as you're only defining them by value. If you want to define your parameters by name you should pass a code block:

def f(x: => Int, y:Int) = x

This way the parameter x will not be evaluated until it's called in the function.

This little post here explains this nicely too.

查看更多
人间绝色
3楼-- · 2019-01-01 03:31

I don't think all the answers here do the correct justification:

In call by value the arguments are computed just once:

def f(x : Int, y :Int) = x

// following the substitution model

f(12 + 3, 4 * 11)
f(15, 4194304)
15

you can see above that all the arguments are evaluated whether needed are not, normally call-by-value can be fast but not always like in this case.

If the evaluation strategy was call-by-name then the decomposition would have been:

f(12 + 3, 4 * 11)
12 + 3
15

as you can see above we never needed to evaluate 4 * 11 and hence saved a bit of computation which may be beneficial sometimes.

查看更多
孤独寂梦人
4楼-- · 2019-01-01 03:32

The example you have given only uses call-by-value, so I will give a new, simpler, example that shows the difference.

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

scala> callByValue(something())
calling something
x1=1
x2=1

scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

查看更多
高级女魔头
5楼-- · 2019-01-01 03:34

Going through an example should help you better understand the difference.

Let's definie a simple function that returns the current time:

def getTime = System.currentTimeMillis

Now we'll define a function, by name, that prints two times delayed by a second:

def getTimeByName(f: => Long) = { println(f); Thread.sleep(1000); println(f)}

And a one by value:

def getTimeByValue(f: Long) = { println(f); Thread.sleep(1000); println(f)}

Now let's call each:

getTimeByName(getTime)
// prints:
// 1514451008323
// 1514451009325

getTimeByValue(getTime)
// prints:
// 1514451024846
// 1514451024846

The result should explain the difference. The snippet is available here.

查看更多
登录 后发表回答