Call by Name & Call by Value
Call by Name
& Call by Value
は関数パラメータの評価戦略を指しています。
相違点としては、評価のタイミングにあります。
Call by Value
item | description |
---|---|
評価タイミング | パラメータ(引数)は関数を渡す前に評価される |
動作 | パラメータの実際の値が計算され、その結果が関数内で使用される |
特徴 | パラメータは一度だけ評価され、その評価された値が関数の中で複数回使われても、再評価は行われない |
Call by Name
item | description |
---|---|
評価タイミング | パラメータは関数の中で実際に使用されるまで評価されない |
動作 | パラメータは関数内で参照されるたびに評価される |
特徴 | パラメータが関数内で一度も使われなければ、そのパラメータの評価も行われない。 関数内で複数回参照される場合は、その都度評価される。 |
Sample code
def methodCallByValue(x: Long): Unit = {
println("Call by value: " + x)
println("Call by value: " + x)
}
def methodCallByName(x: => Long): Unit = {
println("Call by name: " + x)
println("Call by name: " + x)
}
methodCallByValue(System.nanoTime())
methodCallByName(System.nanoTime())
/* output
Call by value: 3529902534708
Call by value: 3529902534708
Call by name: 3529925374833
Call by name: 3529925707125
*/
methodCallByValue -> 一度だけ評価されている
methodCallByName -> xが呼び出されるたびに評価されている
Which Choose?
- Call by Value
他言語でも一般的に利用されていて馴染み深い
パラメータの評価に副作用がないか、パラメータの評価結果を複数回使用する場合に適している
- Call By Name
遅延評価が必要な場合や、条件によってパラメータを評価しない場合に有効
例: 短絡評価(short-circuiting)を行う論理演算など
補足事項
- 短絡評価(short-circuiting)
ブール演算(論理演算)において、結果が最初のオペランドの評価だけで決定できる場合、残りのオペランドを評価しないというテクニック
主にパフォーマンスの最適化や不必要な副作用を避けるために使用されます
def and(a: Boolean, b: => Boolean): Boolean = {
if (a) b else false
}
def testA(): Boolean = {
println("testA called")
false
}
def testB(): Boolean = {
println("testB called")
true
}
println(and(testA(), testB())) // testBは呼ばれない
※ 正格評価の場合、論理演算においえて結果を決定するために必要かどうかかからず、全てのオペランドが評価される
参考文献
Scala & Functional Programming Essentials | Rock the JVM
Programming Scala, 3rd Edition