I understand the basic concept of call-by-name and call-by-value, and I have also looked into handful number of examples. However, I am not very clear about when to use call-by-name. What would be a real-world scenario where call-by-name would have a significant advantage or performance gain over the other call type? What should be the correct thinking approach to select a call type while designing a method?
相关问题
- Unusual use of the new keyword
- Get Runtime Type picked by implicit evidence
- What's the point of nonfinal singleton objects
- PlayFramework: how to transform each element of a
- Error in Scala Compiler: java.lang.AssertionError:
相关文章
- Gatling拓展插件开发,check(bodyString.saveAs("key"))怎么实现
- RDF libraries for Scala [closed]
- Why is my Dispatching on Actors scaled down in Akk
- How do you run cucumber with Scala 2.11 and sbt 0.
- GRPC: make high-throughput client in Java/Scala
- Setting up multiple test folders in a SBT project
- Testing request with CSRF Token in Play framework
- Run project with java options via sbt
Call by name means the value is evaluated at the time it is accessed, while with call by value the value is evaluated first and then passed to the method.
To see the difference, consider this example (completely non-functional programming with only side effects ;) ). Say you want to create a function which measures how much time some operation takes. You can do it with call-by-name:
You will get the result (YMMV):
But if you change only the signature of
measure
tomeasure(action: Unit)
so it uses pass-by-value, the result will be:As you can see, the
action
is evaluated beforemeasure
even starts and also the elapsed time is close to 0 due to the action already having been run before the method was called.Here, pass-by-name allows the expected behavior of the method to be achieved. In some cases it doesn't influence the correctness, but does influence the performance, for example in logging frameworks where a complex expression might not need to be evaluated at all if the result is not used.
When a call-by-name parameter is used more than once in a function, the parameter is evaluated more than once.
As the parameter being passed in should be a pure function call per Functional Programming, each evaluation within the called function will always generate the same result. Therefore, call-by-name would be more wasteful than the conventional call-by-value.
There are plenty of places were call-by-name may gain performance or even correctness.
Simple performance example: logging. Imagine an interface like this:
And then used like this:
If the
info
method doesn't do anything (because, say, the logging level was configured for higher than that), thencomputeTimeSpent
never gets called, saving time. This happens a lot with loggers, where one often sees string manipulation which can be expensive relative to the tasks being logged.Correctness example: logic operators.
You have probably seen code like this:
Say you declared
&&
method like this:then, whenever
ref
isnull
, you'll get an error becauseisSomething
will be called on anull
reference before being passed to&&
. For this reason, the actual declaration is:So one may actually wonder is when to use call-by-value. In fact, in the Haskell programming language everything works similar to how call-by-name works (similar, but not the same).
There are good reasons not to use call-by-name: it is slower, it creates more classes (meaning the program takes longer to load), it consumes more memory, and it is different enough that many have difficult reasoning about it.
The simple way it might be explained is
I've always thought this terminology is needlessly confusing. A function can have multiple parameters which vary in their call-by-name vs call-by-value status. So it's not that a function is call-by-name or call-by-value, it's that each of its parameters may be pass-by-name or pass-by-value. Furthermore, "call-by-name" has nothing to do with names. => Int is a different type from Int; it's "function of no arguments that will generate an Int" vs just Int. Once you've got first-class functions you don't need to invent call-by-name terminology to describe this.