Let's say that I have the following code:
(defclass foo ()
((a :accessor a :initform 1)
(b :accessor b :initform 2)
(c :accessor c :initform 3)))
(defmethod print-object ((self foo) out-stream)
(with-slots (a b c) self
(format out-stream "~S ~S ~S" a b c)))
(defun reset-foo-slots (bar)
"Reinitialize BAR slots."
(let ((slots-to-reset (class-direct-slots (find-class 'foo))))
(loop for slot in slots-to-reset
do (setf (slot-value bar (slot-definition-name slot))
(funcall (slot-definition-initfunction slot))))))
Then I have the following REPL interaction:
CL-USER 18 > (setf x (make-instance 'foo)) ;; Instantiate foo => x
#<FOO 20678DCC>
CL-USER 19 > (setf (a x) 42) ;; Set A slot to 42
42
CL-USER 20 > (setf (b x) 42) ;; Set B slot to 42
42
CL-USER 21 > (setf (c x) 42) ;; Set C slot to 42
42
CL-USER 22 > x
42 42 42
CL-USER 23 > (reset-foo-slots x) ;; Reinitialize all slots
NIL
CL-USER 24 > x ;; Reinitialization is successful
1 2 3
Could you please suggest a way of using a writer method instead of
slot-value. I'm having some sort of mental block: I thought if I got
the writer method using (first (slot-definition-writers slot)) and
funcalled it, it would work, but I'm getting all sorts of problems.
Here's what I'd ideally like to have work:
(defun reset-foo-slots (bar)
(let ((slots-to-reset (class-direct-slots (find-class 'foo))))
(loop for slot in slots-to-reset
do (funcall (first (slot-definition-writers slot))
(funcall (slot-definition-initfunction slot))
bar))))
CL-USER 25 > (reset-foo-slots x)
Error: Argument to apply/funcall is not a function: (SETF A).
1 (abort) Return to level 0.
2 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other
options
CL-USER 26 : 1 >
I need to use the writer method because I have some (defmethod (setf a)
:after ((self foo)) ...) code.
Any help is appreciated. Thank you (but please don't email me because
I'm having a problem with spam and I won't be able to read it). Thank
you in advance.
From: Pascal Costanza
Subject: Re: Using an accessor instead of slot-value
Date:
Message-ID: <3qd1m7FecmabU1@individual.net>
··········@eudoramail.com wrote:
> Could you please suggest a way of using a writer method instead of
> slot-value. I'm having some sort of mental block: I thought if I got
> the writer method using (first (slot-definition-writers slot)) and
> funcalled it, it would work, but I'm getting all sorts of problems.
> Here's what I'd ideally like to have work:
>
>
> (defun reset-foo-slots (bar)
> (let ((slots-to-reset (class-direct-slots (find-class 'foo))))
> (loop for slot in slots-to-reset
> do (funcall (first (slot-definition-writers slot))
> (funcall (slot-definition-initfunction slot))
> bar))))
>
> CL-USER 25 > (reset-foo-slots x)
>
> Error: Argument to apply/funcall is not a function: (SETF A).
> 1 (abort) Return to level 0.
> 2 Return to top loop level 0.
This is a case where it makes sense to read the error message. ;)
funcall is only required to recognize symbols and function objects, but
not conses of the form (setf x).
Try to funcall (fdefinition (first (slot-definition-writers slots))).
Cheers,
Pascal
--
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
Pascal Costanza wrote:
> ··········@eudoramail.com wrote:
>
>> Could you please suggest a way of using a writer method instead of
>> slot-value. I'm having some sort of mental block: I thought if I got
>> the writer method using (first (slot-definition-writers slot)) and
>> funcalled it, it would work, but I'm getting all sorts of problems.
>> Here's what I'd ideally like to have work:
>>
>>
>> (defun reset-foo-slots (bar)
>> (let ((slots-to-reset (class-direct-slots (find-class 'foo))))
>> (loop for slot in slots-to-reset
>> do (funcall (first (slot-definition-writers slot))
>> (funcall (slot-definition-initfunction slot))
>> bar))))
>>
>> CL-USER 25 > (reset-foo-slots x)
>>
>> Error: Argument to apply/funcall is not a function: (SETF A).
>> 1 (abort) Return to level 0.
>> 2 Return to top loop level 0.
>
>
> This is a case where it makes sense to read the error message. ;)
Nah, (SETF A) looks like a function.
The trick is to enter the debugger and inspect the thing being printed
as "(SETF A)".
To the OP: would shared-initialize work for you? That also keeps you out
of the MOP, which is not standard.
--
Kenny
Why Lisp? http://wiki.alu.org/RtL_Highlight_Film
"I've wrestled with reality for 35 years, Doctor, and I'm happy to state
I finally won out over it."
Elwood P. Dowd, "Harvey", 1950
Hi Kenny,
Thanks for replying. My example above was slightly misleading; I'm not
actually doing (defclass foo () ...) but:
CL-USER 1 > (capi:define-interface foo ()
((a :accessor a :initform 1)
(b :accessor b :initform 2)
(c :accessor c :initform 3)))
FOO
CL-USER 2 > (find-class 'foo)
#<CAPI::CAPI-CLASS FOO 20666D3C>
So, I'm using the metaclass capi::capi-class and not the
standard-class. Because I'm unsure about what's going on behind the
define-interface macro, I decided not to try shared-initialize. But
now that I think about it - I'm think I'll just read up on it in case I
missed something elegant.
And yes! From Pascal's answer, I was thinking of (setf a) as a function
and not a cons. Good grief - didn't even know that there was an
fdefinition operator. Seems like a good thing to have around.
Okay, using shared-initialize (with t for its slots-for-initform
argument) is a better all-around solution.
From: Pascal Costanza
Subject: Re: Using an accessor instead of slot-value
Date:
Message-ID: <3qd32eFe0u4sU1@individual.net>
Kenny Tilton wrote:
>
>
> Pascal Costanza wrote:
>
>> ··········@eudoramail.com wrote:
>>
>>> Could you please suggest a way of using a writer method instead of
>>> slot-value. I'm having some sort of mental block: I thought if I got
>>> the writer method using (first (slot-definition-writers slot)) and
>>> funcalled it, it would work, but I'm getting all sorts of problems.
>>> Here's what I'd ideally like to have work:
>>>
>>>
>>> (defun reset-foo-slots (bar)
>>> (let ((slots-to-reset (class-direct-slots (find-class 'foo))))
>>> (loop for slot in slots-to-reset
>>> do (funcall (first (slot-definition-writers slot))
>>> (funcall (slot-definition-initfunction slot))
>>> bar))))
>>>
>>> CL-USER 25 > (reset-foo-slots x)
>>>
>>> Error: Argument to apply/funcall is not a function: (SETF A).
>>> 1 (abort) Return to level 0.
>>> 2 Return to top loop level 0.
>>
>> This is a case where it makes sense to read the error message. ;)
>
> Nah, (SETF A) looks like a function.
Maybe. The HyperSpec says that funcall accepts a function designator as
its first parameter which the glossary defines to be either a symbol or
a function. An extended function designator may also be a list of the
form (setf symbol), but that's not what funcall accepts.
? (defun a () nil)
A
? (defun (setf a) (value) value)
(SETF A)
? (funcall 'a)
NIL
? (funcall '(setf a) 42)
> Error: (SETF A) can't be FUNCALLed or APPLYed.
> While executing: FUNCALL
> Type Command-. to abort.
See the Restarts� menu item for further choices.
1 >
Aborted
? (funcall (fdefinition '(setf a)) 42)
42
Pascal
--
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++