From: ··········@eudoramail.com
Subject: Using an accessor instead of slot-value
Date: 
Message-ID: <1128352014.503512.92490@g49g2000cwa.googlegroups.com>
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 ++++
From: ··········@eudoramail.com
Subject: Re: Using an accessor instead of slot-value
Date: 
Message-ID: <1128357868.775064.56180@g47g2000cwa.googlegroups.com>
Hi Pascal,

Thanks for helping me out.  I haven't had time to try it out your
(funcall (fdefinition ....), but it looks like what I need.

Thanks again.
From: Kenny Tilton
Subject: Re: Using an accessor instead of slot-value
Date: 
Message-ID: <olc0f.8005$wf6.1205298@twister.nyc.rr.com>
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
From: ··········@eudoramail.com
Subject: Re: Using an accessor instead of slot-value
Date: 
Message-ID: <1128357592.004369.182650@g44g2000cwa.googlegroups.com>
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.
From: ··········@eudoramail.com
Subject: Re: Using an accessor instead of slot-value
Date: 
Message-ID: <1128359888.083069.273000@o13g2000cwo.googlegroups.com>
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 ++++