I have a list which contains some symbols and values. The goal is to setf the class slot with the accessor, whose symbol is provided by the list :
(defclass my-class ()
((attr :accessor attr)))
(let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(setf `(,(car to-call) obj) (cadr to-call)))
I have tried via a macro :
(defmacro call-accessor (to-call)
`(setf (,(car to-call) obj) "some-value"))
(let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(call-accessor to-call))
Which fails too, since to-call
is a symbol and not a list.
eval
does not work since to-call
is a lexical variable; let
over the macro to give it the list;with-slots
and with-accessors
but the problem remains the same, because they are macros too.How can I setf a slot via an accessor corresponding to a symbol in my list ?
Thank you.
Calling the accessor function
The goal is to setf the class slot with the accessor
An accessor is a pair of functions. You can get the part which sets the value via FDEFINITION
. The name of the function is a list (SETF accessor-name )
. This is unusual: Common Lisp has in this case function names which are not symbols, but lists.
CL-USER 14 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(funcall (fdefinition `(setf ,(first to-call)))
(second to-call)
obj)
(describe obj))
#<MY-CLASS 40200614FB> is a MY-CLASS
ATTR "some-value"
Using a function call-accessor
:
CL-USER 25 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(flet ((call-accessor (obj to-call)
(funcall (fdefinition `(setf ,(first to-call)))
(second to-call)
obj)))
(call-accessor obj to-call)
(describe obj)))
#<MY-CLASS 402000220B> is a MY-CLASS
ATTR "some-value"
using SETF with APPLY to hide the FDEFINITION call
To use setf
with a computed accessor, one might need to use an apply
form and a custom function.
Something like call-accessor
would naturally be a function, because it does runtime lookup and takes values. Trying to use a macro would be more useful if the accessor would be known at compile time.
CL-USER 23 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(flet (((setf my-setter) (new-value object accessor)
(funcall (fdefinition `(setf ,accessor))
new-value
obj)))
(flet ((call-accessor (obj to-call)
(setf (apply #'my-setter obj (list (first to-call)))
(second to-call))))
(call-accessor obj to-call)
(describe obj))))
#<MY-CLASS 40200009AB> is a MY-CLASS
ATTR "some-value"
Choice of data structure
I think it's okay to compute accessor functions and similar. There may be use cases for that. CLOS was designed to be dynamic and reflective to allow these things.