;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: Introduction to Generalized Variables =Text: 3INTRODUCTION TO GENERALIZED VARIABLES* In Lisp, a variable is something that can remember one piece of data. The primary conceptual operations on a variable are to recover that piece of data and to change it. These might be called 1access* and 1update*. The concept of variables named by symbols, explained above, can be generalized to any storage location that can remember one piece of data, no matter how that location is named. For each kind of generalized variable, there are typically three functions which implement the conceptual 1access*, 1update* and 1locate* operations. For example, 2symeval* accesses a symbol's value cell, 2set* updates it, and 2value-cell-location* returns the value cell's location. 2array-leader* accesses the contents of an array leader element, 2store-array-leader* updates it, and 2ap-leader* returns the location of the leader element. 2car* accesses the car of a cons, 2rplaca* updates it, and 2car-location* returns the location of the car. Rather than thinking of this as two functions, which operate on a storage location somehow deduced from their arguments, we can shift our point of view and think of the access function as a 1name* for the storage location. Thus 2(symeval 'foo)* is a name for the value of 2foo*, and 2(aref a 105)* is a name for the 105th element of the array 2a*. Rather than having to remember the update function associated with each access function, we adopt a uniform way of updating storage locations named in this way, using the 2setf* special form. This is analogous to the way we use the 2setq* special form to convert the name of a variable (which is also a form which accesses it) into a form that updates it. In fact, 2setf* is an upward compatible generalization of 2setq*. Similarly, the location of the generalized variable can be obtained using the 2locf* construct. =Node: setf =Text: 3SETF* 2setf* is the construct for storing a new value into a generalized variable which is identified by the form which would obtain the current value of the variable. For example, 3(setf (car x) y)* stores the value of 2y* into the car of the value of 2x*. 2setf* is particularly useful in combination with structure-accessing macros, such as those created with 2defstruct*, because the knowledge of the representation of the structure is embedded inside the macro, and the programmer shouldn't have to know what it is in order to alter an element of the structure. 2setf* is actually a macro which expands into the appropriate update code. It has a database, explained in 4(MACROS-3)Extending setf and locf*, that associates from access functions to update functions. 3setf* 1{place* 1value}...* 1Macro* Takes a form called 1place* that 1accesses* something and ``inverts'' the form to produce a corresponding form to 1update* the thing. A 2setf* expands into an update form, which stores the result of evaluating the form 1value* into the place referenced by the 1place*. If multiple 1place*`s and 1value*`s are specified, each one specifies an update, and each update is done before the following updates' arguments are computed. Examples: 3(setf (array-leader foo 3) 'bar)* 3 ==> (store-array-leader 'bar foo 3)* 3(setf a 3) ==> (setq a 3)* 3(setf (plist 'a) '(foo bar)) ==> (setplist 'a '(foo bar))* 3(setf (aref q 2) 56) ==> (sys:set-aref q 2 56)* 3(setf (cadr w) x) ==> (sys:setcdr (cdr w) x)* The value of a 2setf* form is always the 1value* stored by the last update it performs. Thus, 2(setf (cadr w) x)* is not really the same as 2(rplaca (cdr w) x)*, because the 2setf* returns 2x* and the 2rplaca* returns 2w*. In fact, the expansion of 2setf* of 2cdr* uses an internal function 2si:setcdr* which exists specifically for this purpose. If 1place* invokes a macro or a substitutable function, then 2setf* expands the 1place* and starts over again. This lets you use 2setf* together with 2defstruct* accessor macros. 3sys:unknown-setf-reference* (error) 1Condition* 3sys:unknown-locf-reference* (error) 1Condition* These are signaled when 2setf* or 2locf* does not know how to expand the 1place*. The 2:form* operation on the condition instance returns the 1access-form*. 3psetf* 1{place* 1value}...* 1Macro* Stores each 1value* into the corresponding 1place*, with the changes taking effect in parallel. Thus, 3(psetf (car x) (cdr x) (cdr x) (car x))* interchanges the car and cdr of 2x*. The subforms of the 1place*s, and the 1values*, are evaluated in order; thus, in 3(psetf (aref a (tyi)) (tyi)* 3 (aref b (tyi)) (aref a (tyi)))* the first input character indexes 2a*, the second is stored, the third indexes 2b*, and the fourth indexes 2a*. The parallel nature of 2psetf* implies that, should the first and fourth characters be equal, the old value of that element of 2a* is what is stored into the array 2b*, rather than the new value which comes from the second character read. 3shiftf* 1place...* 1Macro* Sets the first 1place* from the second, the second from the third, and so on. The last 1place* is not set, so it doesn't really need to be a 2setf*'able place; it can be any form. The value of the 2shiftf* form is the old value of the first 1place*. Thus, 3(shiftf x (car (foo)) b)* evaluates 2(foo)*, copies the car of that value into 2x*, copies 2b* into the car of that value, then returns the former value of 2x*. 3rotatef* 1place...* 1Macro* Sets the first 1place* from the second, the second from the third, and so on, and sets the last 1place* from the old value of the first 1place*. Thus, the values of the 1place*'s are permuted among the 1place*'s in a cyclic fashion. With only two 2place*'s, their values are exchanged: 3(rotatef (car x) (cdr x))* is equivalent to the 2psetf* example above. 3swapf* 1place1* 1place2* 1Macro* Exchanges the contents of 1place1* and 1place2*. This is a special case of 2rotatef*. 3incf* 1place* 1[amount]* 1Macro* Increments the value of a generalized variable. 2(incf 1ref*)* increments the value of 1ref* by 1. 2(incf 1ref* 1amount*)* adds 1amount* to 1ref* and stores the sum back into 1ref*. The 2incf* form returns the value after incrementation. 2incf* expands into a 2setf* form, so 1ref* can be anything that 2setf* understands as its 1place*. 2incf* is defined using 2define-modify-macro*, 4(MACROS-3)Extending setf and locf*. 3decf* 1place* 1[amount]* 1Macro* Decrements the value of a generalized variable. Just like 2incf* except that 1amount* (or 1) is subtracted rather than added. See also 2push* (4(MANLISTSTR-1)Conses*), 2pop* (4(MANLISTSTR-1)Conses*), 2pushnew* (4(MANLISTSTR-2)Lists as Sets*), 2getf* (4(MANLISTSTR-2)Property Lists*) and 2remf* (4(MANLISTSTR-2)Property Lists*). =Node: locf =Text: 3LOCF* Besides the 1access* and 1update* conceptual operations on generalized variables, there is a third basic operation, which we might call 1locate*. Given the name of a storage cell, the 1locate* operation returns the address of that cell as a locative pointer (see 4(LOCATIVES-0)Locatives*). This locative pointer is a first-class Lisp data object which is a kind of reference to the cell. It can be passed as an argument to a function which operates on any cell, regardless of where the cell is found. It can be used to 1bind* the contents of the cell, just as special variables are bound, using the 2%bind* subprimitive (see 4(SUBPRIMITIVES-2)Special-Binding Subprimitive*). Of course, this can work only on generalized variables whose implementation is really to store their value in a memory cell. A generalized variable with an 1update* operation that encrypts the value and an 1access* operation that decrypts it could not have the 1locate* operation, since the value per se is not actually stored anywhere. 3locf* 1place* 1Macro* 2locf* takes a form that 1accesses* some cell, and produces a corresponding form to create a locative pointer to that cell. Examples: 3(locf (array-leader foo 3)) ==> (ap-leader foo 3)* 3(locf a) ==> (value-cell-location 'a)* 3(locf (plist 'a)) ==> (property-cell-location 'a)* 3(locf (aref q 2)) ==> (aloc q 2)* If 1place* invokes a macro or a substitutable function, then 2locf* expands the 1place* and starts over again. This lets you use 2locf* together with 2defstruct* accessor macros.