;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: Cells and Locatives =Text: 3CELLS AND LOCATIVES* A 1locative* is a type of Lisp object used as a 1pointer* to a 1cell*. Locatives are inherently a more low level construct than most Lisp objects; they require some knowledge of the nature of the Lisp implementation. A 1cell* is a machine word that can hold a (pointer to a) Lisp object. For example, a symbol has five cells: the print name cell, the value cell, the function cell, the property list cell, and the package cell. The value cell holds (a pointer to) the binding of the symbol, and so on. Also, an array leader of length 1n* has 1n* cells, and an 2art-q* array of 1n* elements has 1n* cells. (Numeric arrays do not have cells in this sense.) A locative is an object that points to a cell; it lets you refer to a cell so that you can examine or alter its contents. 3contents* 1locative* Returns the contents of the cell which the locative points to. This is actually the same as 2cdr*, for reasons explained below, but it is clearer to use 2contents* when the argument is normally a locative. To modify the contents of the cell, use 2setf* on 2contents*: 3(setf (contents loc) newvalue)* The macro 2locf* (see 4(EVAL-2)locf*) can be used to convert a form that accesses a cell to one that creates a locative pointer to that cell: for example, 3(locf (fsymeval x))* evaluates to a locative that points to the function cell of the value of 2x*; that is to say, it points to the place where 2(fsymeval x)* is stored. 2locf* is very convenient because it saves the writer and reader of a program from having to remember the names of many functions that would create locatives to cells found in different fashions. One thing you should know is that it is not possible to make a locative to an element of a numeric array. For example, 3(setq foo (make-array 10 :type art-1b))* 3(locf (aref foo 0))* signals an error. Locatives may only point at entire words of memory, which contain standard Lisp data. Because of cdr-coding (see 4(MANLISTSTR-1)Cdr-Coding*), a cons does not always contain an explicit cell which points to its cdr. Therefore, it is impossible to obtain a locative which points to such a cell. However, this is such a useful thing to do that 1the cons itself* is usually treated as if it were a locative pointing to a cell which holds the cons's cdr. 2(locf (cdr x))* returns the value of 2x*, and 2(contents x)* returns the cdr when 1x* is a cons, so 2(contents (locf (cdr x)))* is the same as 2(cdr x)*, as it should be. Most functions that are normally given locatives also accept a cons and treat it as if it were a magic locative to the (nonexistent) cell containing the cdr of the cons. A cons always does contain a cell which points to the car, and 2(locf (car x))* returns a locative whose pointer field is the same as that of 2x*'s value. =Node: Functions That Operate on Locatives =Text: 3FUNCTIONS THAT OPERATE ON LOCATIVES location-boundp* 1locative* Returns 2t* if the cell to which 1locative* points contains anything except a void marker. The void marker is a special data type, 2dtp-null*, which is stored in cells to say that their value is missing. For example, an unbound variable actually has a void marker in its value cell, and 2(location-boundp (locf x))* is equivalent to 2(variable-boundp x)*. 3location-makunbound* 1locative* &optional 1pointer* Stores a void marker into the cell to which 1locative* points. This consists of data type field 2dtp-null* and a pointer copied from 1pointer*. The pointer field of the void marker is used to tell the error handler what variable was unbound. In the case of a symbol's value cell or function cell, it should point to the symbol header. In the case of a flavor method, it should point to the beginning of the block of data that holds the definition, which is a word containing the method's function spec. If the second arg is not specified, then where the void marker points is not defined. Other functions with which locatives are expected or useful include 2get* (the locative points to the cell in which the plist is stored), 2store-conditional* (the locative points to the cell to be tested and modified), and 2%bind* (the locative points to the cell to be bound). =Node: Mixing Locatives with Lists =Text: 3MIXING LOCATIVES WITH LISTS* Either of the functions 2car* and 2cdr* (see 4(MANLISTSTR-1)Conses*) may be given a locative, and will return the contents of the cell at which the locative points. They are both equivalent to 2contents* when the argument is a locative. Similarly, either of the functions 2rplaca* and 2rplacd* may be used to store an object into the cell at which a locative points. For example, 3(rplaca locative y)* or 3(rplaca locative y)* is the same as 3(setf (contents locative) y)* If you are just using locatives, you should use 2contents* rather than 2car* or 2cdr*. But you can also mix locatives and conses. For example, the same variable may usefully sometimes have a locative as its value and sometimes a cons. Then it is useful that 2car* and 2cdr* work on locatives, and it also matters which one you use. Pick the one that is right for the case of a cons. For example, the following function conses up a list in the forward order by adding onto the end. It needs to know where to put the pointer to the next cell. Usually it goes in the previous cell's cdr, but the first cell gets put in the cell where the list is supposed to end up. A locative is used as the pointer to this cell. The first time through the loop, the 2rplacd* is equivalent to 2(setq res ...)*; on later times through the loop the 2rplacd* tacks an additional cons onto the end of the list. 3(defun simplified-version-of-mapcar (fcn lst)* 3 (do ((lst lst (cdr lst))* 3 (res nil)* 3 (loc (locf res)))* 3 ((null lst) res)* 3 (setf (cdr loc)* 3 (setq loc (ncons (funcall fcn (car lst)))))))* 2cdr* is used here rather than 2contents* because the normal case is that the argument is a list.