7

In most programming languages, arguments passed to a function are evaluated before the function uses them, that is, they are evaluated eagerly.

To me, it seems like it would make much more sense to evaluate the arguments only once the function uses them, that is, lazily. This makes more sense to me because it seems like it would have a performance benefit: why evaluate things that are never even needed?

Moreover, suppose you wanted to implement an if function that accepts a boolean, and an object to return if the boolean is true, and another object to return if the boolean is false:

object if(bool condition, object valueIfTrue, object valueIfFalse) {
  if(condition) return valueIfTrue;
  return valueIfFalse;
}

In a language that eagerly evaluates arguments, both objects are always evaluated even though the function will always only need one of them, which, at best, incurs a slight unecessary overhead, and, at worst, causes an infinite loop.

That said, since most programming languages use eager evaluation of function arguments, I assume there must be a reason why it's usually done that way. Is there some big benefit of eager evaluation here that I'm overlooking, is it just because it was easier to implement languages that way, is it just tradition, or what?

Peter Olson
  • 139,199
  • 49
  • 202
  • 242

5 Answers5

6

There are a couple reasons I've seen for eager evaluation, both of which are important:

  1. Eager evaluation means that side effects happen immediately and always. If you use lazy evaluation, you can't rely on the side effects of something you've done previously to have taken effect.
  2. Lazy evaluation brings with it a certain amount of memory bloat. It generally takes much less memory to store the result of a calculation than it does to store the thunk that describes the calculation. This can lead to using too much memory (ie, time vs. memory tradeoffs) and, sometimes more importantly, a harder time figuring out the memory characteristics of the program/algorithm.

Lazy evaluation can be a powerful tool, but it's not without it's costs. Purely functional languages tend to avoid problem #1 because they don't have side effects (in general), but are still bitten by problem #2 at times. Languages that allow delayed evaluation (LISP macros are a form of this, though not the same as lazy evaluation) can have the best of both worlds, but at the cost of more effort on the programmer's part.

RHSeeger
  • 16,034
  • 7
  • 51
  • 41
3

Option 1 - load all arguements into registers, call function

Option 2 - load first argument, evaluate if it's necessary, wait for CPU pipeline to clear, get next argument, evaluate if it's necessary .... then load needed paramters into registers, execute function with extra logic to mark which registers are in use.

An 'if' is already going to cause a performance holdup anyway while you wait to see which code path you are executing (slightly saved by branch prediction)

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
3

In order for lazy evaluation to work there needs to be extra code and data somewhere to keep track of whether an expression has been evaluated. In some cases this would be more costly than eager evaluation. Determining whether an expression can benefit from lazy evaluation may require a very high-level knowledge of how the program works; the compiler and/or interpreter certainly won't have this kind of knowledge.

Also, if the function or expression have side effects, the lazy evaluation strategy might make programs behave in ways that are counterintuitive and hard to debug. This is of course not a problem in functional programming languages where there are no side effects by design. In fact, lazy evaluation is the default strategy for most, if not all, functional programming languages.

That being said, there's nothing that prevents you from using both strategies in different places. I wouldn't be surprised if a hybrid approach is used in non-trivial programs.

In silico
  • 51,091
  • 10
  • 150
  • 143
2

Apart from the excellent answers already provided, there's another practical problem with lazy evaluation. If you have a chain of expressions only lazily evaluated when the last one is "used", it can become quite hard to identify performance bottlenecks.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • Can you give an example? I'm trying to visualize the sort of code you're talking about. – Peter Olson Jan 10 '12 at 04:03
  • Well, suppose you have an argument `x` to a function which itself when evaluated gets the value of another variable `y` and this kind of chain goes back. There might be some evaluations which are slow and which are bottlenecks but you'll see them when you evaluate `x`. That can be misleading and the origin sometimes hard to track down. – Noufal Ibrahim Jan 10 '12 at 04:13
0

Back in the Cretaceous Period, there were a number of languages that did this. SNOBOL, for example. ALGOL 68 had a "call by name" capability, which did something like this. And C (as well as its many derivatives) does it in one very specific situation, which it describes as "short-circuiting" a boolean expression. In general, it is almost always a source of more confusion and bugs than it is of enabling power.

Ross Patterson
  • 9,527
  • 33
  • 48
  • I don't think Algol's call by name was lazy evaluation, I think that was passing references instead of values. – Peter Olson Jan 12 '12 at 01:09
  • ALGOL's call by name was more of a textual-substitution and explicitly not a reference, so I think it qualifies as lazy evaluation. Although now that I think about it, it might have been ALGOL 60 that introduced it, not ALGOL 68. – Ross Patterson Jan 12 '12 at 17:24
  • 1
    Ahh... the 1960s, the "[Cretaceous Period](http://stackoverflow.com/questions/1463321/was-algol-ever-used-for-mainstream-programming)" when we were giants and walked on the moon... :-) Algol60 has call by name. Algol68 does not have call by name, however 68 does have call by reference. And further,... lazy evaluation can be implemented in a program by the coder by using "proceduring", c.f. [Short circuit evaluation using procedures](http://stackoverflow.com/questions/9462051/short-circuit-evaluation-using-procedures) – NevilleDNZ Apr 02 '12 at 00:48