I am not sure what is going on here, a macro example in the text. Basically, not comfortable with how to use get-setf-method, a built-in macro (maybe function?). To be specific, how about the case that some of the return values of get-setf-method are nil? e.g. (get-setf-method 'x)
NIL ;
NIL ;
(#:NEW-3069) ;
(SETQ X #:NEW-3069) ;
X
And why this example code set the fifth return value to the second return value first, for initialization? Finally how it can handle the order of setting the variables in an expression, such as (aref ar (incf i)
(get-setf-method '(aref ar (incf i)))
(#:G3070 #:G3071) ;
(AR (INCF I)) ;
(#:G3072) ;
(SYSTEM::STORE #:G3070 #:G3071 #:G3072) ;
(AREF #:G3070 #:G3071)
Here is the definition of the macro :
(defmacro sortf (op &rest places)
(let* ((meths (mapcar #'(lambda (p)
(multiple-value-list
(get-setf-method p)))
places))
(temps (apply #'append (mapcar #'third meths))))
`(let* ,(mapcar #'list
(mapcan #'(lambda (m)
(append (first m)
(third m)))
meths)
(mapcan #'(lambda (m)
(append (second m)
(list (fifth m))))
meths))
,@(mapcon #'(lambda (rest)
(mapcar
#'(lambda (arg)
`(unless (,op ,(car rest) ,arg)
(rotatef ,(car rest) ,arg)))
(cdr rest)))
temps)
,@(mapcar #'fourth meths))))
That's actually some older code.
get-setf-method
was actually replaced byget-setf-expansion
as described in Issue SETF-METHOD-VS-SETF-METHOD Writeup. So what you should be interested in these days isget-setf-expansion
. The values that it returns are the pieces of code that you need to safely store a value in a location. This is very important because it's very easy to write modyfing macros incorrectly.As to why some of the values can be
nil
, one of the examples in the documentation forget-setf-expansion
actually shows how some of the values can benil
:But what are those values? For that we need to look at the syntax of the documentation:
Those five return values are described in 5.1.1.2 Setf Expansions:
So what do those values in the example mean?
To write to variable
x
, we don't need any temporary storage, and since there are no temporary values, we don't need any forms to produce values for them. We can notice here that the first and second values are always lists, and they should always have the same length. The third value is a list of store variables. This is a list, because we can actually usesetf
to modify multiple values, but in this case there's just one. The variables here are where the macro should actually store the new values for the place. Then, it's the writer-form(setq x #:g0001)
that will actually take care of putting the value in the place.x
, of course, is a simple way of reading the value.As a more complex example, have a look at this transcript from SBCL:
This means that if we wanted to change the fourth character of the name of the first person in the second list of persons in a list of lists of persons, we could do it with:
We can compute the new value however we want (just fill in for
<compute-new-value>
), and we can even reference the old value if we want to (by including the optional line). All we need to do is setnew964
to the new value, and then execute the writer-form that was given to us.There are more examples of
get-setf-expansion
on Stack Overflow: