Consider this piece of code:
(defvar lst '(1 1))
(defmacro get-x (x lst)
`(nth ,x ,lst))
(defun get-y (y lst)
(nth y lst))
Now let us assume that I want to change the value of the elements of the list called lst, the car with get-x and the cdr with get-y.
As I try to change the value with get-x (with setf) everything goes fine but if I try it with get-y it signals an error (shortened):
; caught STYLE-WARNING:
; undefined function: (SETF GET-STUFF)
Why does this happen?
I myself suspect that this happens because the macro simply expands and the function nth simply returns a reference to the value of an element in the list and the function on the other hand evaluates the function-call to nth and returns the value of the referenced value (sounds confusing).
Am I correct in my suspicions?
If I am correct then how will one know what is simply a reference to a value and an actual value?
The error does not happen with the macro version, because, as you assumed, the expression
(setf (get-x some-x some-list) some-value)will be expanded (at compile-time) into something like(setf (nth some-x some-list) some-value)(not really, but the details ofsetf-expansion are complex), and the compiler knows, how to deal with that (i.e., there is a suitablesetfexpander defined for functionnth).However, in the case of
get-y, the compiler has nosetfexpander, unless you provide one. The easiest way to do so would beNote, that there are a few conventions regarding
setf-expanders:setffunctionsetffunctions are supposed to return the new value as their result (as this is, what the entiresetfform is supposed to return)There is, BTW, no such concept as a “reference” in Common Lisp (at least not in the C++ sense), though there once were Lisp dialects which had locatives. Generalized place forms (ie.,
setfand its machinery) work very differently from plain C++ style references. See the CLHS, if you are curious about the details.