Currently learning common lisp, following Peter Seibel's Practical Common Lisp (i'm at chapter 11, about collections), i have difficulties to understand how setf
works behind the hood.
Considering this expression :
(setf a 10)
I completely understood how the interpreter can (1) retrieve the variable named a
, and (2) change the value it points to to 10
.
Now, i case of particular collections, for instance lists, vectors or hash tables, setf can also be used to change values contained by the collection. For instance, with a vector :
(defparameter *x* '(a b c d))
(setf (elt *x* 1) bb)
This makes me suspicious about setf
, because it is eventually finding non-trivially accessible information, or making black magic. I see multiple possibilities.
1. setf is a function
The (elt *x* 1)
expression is returning 'b
, so setf
is virtually working with (setf b bb)
. I then do not understand how setf
can infer which object (here, the list *x*
) it must modify, without having the return value of elt
holding both an indication that it comes from a collection, and a pointer to the said collection.
Seems complicated.
2. setf is a macro
The idea is, as setf
is a macro, it works directly with the (setf (elt *x* 1) bb)
and therefore can extract the elt *x* 1
part to infer which object/collection is used, and therefore must be modified.
It do not seems very efficient, nor reliable, nor resistant to complex operations. However, since i'm unable to run this code :
(funcall (find-symbol (concatenate 'string "E" "LT")) *x* 1) ; -> B
(setf (funcall (find-symbol (concatenate 'string "E" "LT")) *x* 1) 'bb) ; -> ERROR : (SETF FUNCALL) is only defined for functions of the form #'symbol
This make me think that setf
is a macro implementing a very simple heuristic to retrieve the function to call, and all other needed information.
Seems complicated.
3. setf is a special case of interpretation
Another way to go could be to have setf be handled differently by the interpreter itself, dealing with some black magic to implement properly the expected behavior. Seems complicated.
4. there is something i do not know about lisp
Probably the real answer. What did i miss ?
Bonus question : is the implementation method dependent of the lisp interpreter implementation ? (or, more simply, what exactly the common lisp standard define about setf implementation) I'm currently using clisp but insights on others implementations are welcome.