Last update January 22, 2009

Doc Comments /
Lazy Evaluation



Lazy Evaluation of Function Arguments

Comments

The feature that the document describes is call-by-name, not lazy evaluation of function arguments.

The difference between the two is that with lazy evaluation of function arguments, an argument is evaluated the first time its value is used, whereas with call by name, the value of an argument is evaluated every time the value of the argument is used. (In Algol 60, call by name parameters can be assigned to if the actual parameter is an L-value, but that's not an inherent feature of call by name.)

Lazy evaluation of function arguments addresses the problem described at the start of the paper: avoiding unnecessary evaluations of parameters that aren't used. Lazy evaluation is the theoretically optimal solution to this problem. Parameters are never evaluated more than once, and are not evaluated at all unless their values are required, so it is impossible to define a parameter passing scheme which performs fewere parameter evaluations.

The benefits of lazy evaluation could be achieved by using call by name and ensuring that you don't use the parameter more than once, but it's not always possible to do that without breaking encapsulation. Suppose you add a trace file to your application, to help with debugging. Your trace function is very similar to the logging function:

void trace(lazy char[] message)
{
        if (debugging)
                fwritefln(tracefile, message);
}

You want some of the log messages to go to the trace file, so you write the following function to do this:

void log_and_trace(lazy char[] message)
{
        trace(message);
        log(message);
}

Then you turn on both logging and debugging.

If D used lazy evaluation, then whenever log_and_trace was called its argument would be evaluated only once. But since it apparently uses call by name, the argument is evaluated twice. To avoid this double evaluation, we have to make the function more complicated, and worse, we have to make it depend on the internals of the trace and log functions:

void log_and_trace(lazy char[] message)
{
        if (logging || debugging) {
                char temp[] = message;
                trace(temp);
                log(temp);
        }
}

So call by name is not a perfect substitute for lazy evaluation of function arguments.

Conversely, call by name can be used to implement control abstractions which cannot be implemented using lazy evaluation. The dotimes function in the document is an example.

I don't have a clear-cut opinion on whether D should support call by name or lazy evaluation of function arguments. The document suggests that you tried to implement the latter and got it wrong. If you are convinced that what you implemented is what you want, or close enough to what you want that it's not worth changing at this point, then the thing to do would be to avoid confusion by going through this document, and other D documentation, changing "lazy evaluation of function arguments" to "call by name."

Links

Corresponding page in the D Specification

FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: January 22, 2009 3:59 (diff))