Page:AIM-453.djvu/35

From Wikisource
Jump to navigation Jump to search
There was a problem when proofreading this page.
Steele and Sussman
33
The Art of the Interpreter

other's behavior. This the essence of side effect.

The concept of side effect is induced by particular choices of boundaries between parts of a larger system. If a system boundary encloses all processes of interest (the system is closed), we need no concept of side effect to describe that system as a whole in vacuo. If, however, we wish to make an abstraction by dividing the system into modules more than one of which has independent state, then we have by this action created the concept of side effect.

We are forced to introduce side effects as a technique for constructing modular systems. But side effects violate referential transparency by altering the meanings of expressions; we expect (+ 3 4) always to mean the same thing, but we cannot say the same for (+ 3 (RANDOM)). Two techniques for achieving modularity have come into direct conflict.

The most common form of side effect in programming languages is the assignment statement, which alters the meaning of a variable. LISP provides this notion in the SETQ construct:

(SETQ X 43)

returns 43, and as a side effect alters the meaning of X so that subsequent references will obtain 43 also.

With this, George can now write:

(DEFINE (MAPCAR F L)
        (MAPCAR1 F L (SETQ N (+ N 1))))

(DEFINE (MAPCAR1 F L HUNOZ)
        (OLDMAPCAR F L))

There are still some minor problems here. The function MAPCAR1 and the variable HUNOZ are used solely to throw away the value of the SETQ form. It is so common to use SETQ only for its side effect that another construction, PROGN, is very useful:

(PROGN e1 e1 ... eN)

evaluates each of the forms ej in order, throwing away the values of all but the last one. Notice that we specifically require them to be evaluated in order; this concept did not occur in the specification of our earlier interpreters, because it was not necessary in the absence of side effects. Similarly, it was not useful to be able to throw away values in the absence of side effects. (We did throw away a value in DRIVER-LOOP, but that was one which resulted from calling PRINT, which of course is assumed to have a side effect!) Using PROGN, George can write:

(DEFINE (MAPCAR F L)
        (PROGN (SETQ N (+ N 1))
               (OLDMAPCAR F L)))