From: Jim Newton
Subject: setf with accessors
Date: 
Message-ID: <2uaj78F28v7gtU1@uni-berlin.de>
I have a conceptual question about setf.

I already have the following class with accessors x-coord and y-coord.

(defclass state ()
   (( x
      :accessor x-coord)
    ( y
      :accessor y-coord)

    ;; and several other slots
))


So the following works just great.

  (let (( obj (make-instance 'state)))
      ...
      (setf (x-coord obj) 100)
       ...
)

Now, i want to create a new class which encapsulates a vector.  I want
the class to imply semantics of the vector.  I want to refer to it
as a point-3d so i can write methods specializing on point-3d object
and not mix them up with other objects which might just happend to
be vectors of 3 elements.


(defclass point-3d ()
    (( vec
       :reader vec
       :initform (make-array ( 3 3)
			   :initial-element 0.0
			   :element-type 'single-float
			   :adjustable nil))))

Now i want to use x-coord, y-coord and z-coord on an instance of
class point-3d in order to access the 0'th 1'st and 2'nd elements
of the vector.

(let (( obj (make-instance 'point-3d)))
    ...
    ;; equivalent to (setf (aref (vec obj) 0) 100)
    (setf (x-coord obj) 100)

    ;; equivalent to (setf (aref (vec obj) 2) 200)
    (setf (z-coord obj) 200)

)


Question:
How can i set up the setf mapping?  And do i need to be
concerned that x-coord and y-coord are already defined as
generic functions because of my other class definition
(state)?

Or am i thinking about this completely incorrectly?

-jim

From: Barry Margolin
Subject: Re: setf with accessors
Date: 
Message-ID: <barmar-615990.20111127102004@comcast.dca.giganews.com>
In article <···············@uni-berlin.de>,
 Jim Newton <·····@rdrop.com> wrote:

> I have a conceptual question about setf.
> 
> I already have the following class with accessors x-coord and y-coord.
> 
> (defclass state ()
>    (( x
>       :accessor x-coord)
>     ( y
>       :accessor y-coord)
> 
>     ;; and several other slots
> ))
> 
> 
> So the following works just great.
> 
>   (let (( obj (make-instance 'state)))
>       ...
>       (setf (x-coord obj) 100)
>        ...
> )
> 
> Now, i want to create a new class which encapsulates a vector.  I want
> the class to imply semantics of the vector.  I want to refer to it
> as a point-3d so i can write methods specializing on point-3d object
> and not mix them up with other objects which might just happend to
> be vectors of 3 elements.
> 
> 
> (defclass point-3d ()
>     (( vec
>        :reader vec
>        :initform (make-array ( 3 3)
> 			   :initial-element 0.0
> 			   :element-type 'single-float
> 			   :adjustable nil))))
> 
> Now i want to use x-coord, y-coord and z-coord on an instance of
> class point-3d in order to access the 0'th 1'st and 2'nd elements
> of the vector.
> 
> (let (( obj (make-instance 'point-3d)))
>     ...
>     ;; equivalent to (setf (aref (vec obj) 0) 100)
>     (setf (x-coord obj) 100)
> 
>     ;; equivalent to (setf (aref (vec obj) 2) 200)
>     (setf (z-coord obj) 200)
> 
> )
> 
> 
> Question:
> How can i set up the setf mapping?  And do i need to be
> concerned that x-coord and y-coord are already defined as
> generic functions because of my other class definition
> (state)?

You can set up the SETF mapping by defining methods for the generic 
functions, e.g.:

(defmethod (setf x-coord) (new-value (self point-3d))
  (setf (aref (vec self) 0) new-value))

You don't need to be concerned -- generic functions are intended to have 
methods defined in different classes.  As long as they all have the 
conforming signatures, everything is fine.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Pascal Costanza
Subject: Re: setf with accessors
Date: 
Message-ID: <clpeip$s3j$1@newsreader2.netcologne.de>
Jim Newton wrote:

> Question:
> How can i set up the setf mapping?

Just define new methods:

(defmethod (setf x-coord) (new-value (obj point-3d))
   (setf (aref (vec obj) 0) new-value))

etc.


> And do i need to be
> concerned that x-coord and y-coord are already defined as
> generic functions because of my other class definition
> (state)?

No. By default, all kinds of methods can be added to generic functions. 
The generic functions that are implicitly generated by accessors are in 
no way special in that regard.

However, it is probably a good idea to document that you intend to 
define your own methods by defining explicit generic functions like this:

(defgeneric x-coord (obj))
(defgeneric (setf x-coord) (new-value obj))

etc.

This tells the reader of your program code that you intend to explicitly 
add methods and don't just want to have the implicitly generated ones. 
(I have stolen that advice from Scott McKay. ;)

> Or am i thinking about this completely incorrectly?

No, I don't think so. But note that you are duplicating things to a 
certain extent. CLOS implementations usually map slots to arrays on the 
lowest level, and if they want to conform to the MOP specification they 
have to. The CLOS MOP defines standard-instance-access as a way to 
directly access slots by indices. (But this probably doesn't really 
matter in practice since some MOP implementations don't provide it or 
deviate from the spec. CLOS implementations usually do a good job at 
implementing accessor methods efficiently, so efficiency doesn't seem to 
be a good reason to use standard-instance-access anyway.)


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Jim Newton
Subject: Re: setf with accessors
Date: 
Message-ID: <2ubiq4F28kkm9U1@uni-berlin.de>
thanks for the information about the MOP.  however i think
i need the explicit array here because i want to be able
to access the data by x-coord and y-coord functions sometimes
for clarity, but i also want to be able to do looping
manipulations over the rows and columns of vectors and
matrices.

a simple example.

(loop for row from 0 below 3
    (incf (aref (vec obj1) row) (aref (vec obj2) row)))


Pascal Costanza wrote:
> 
> Jim Newton wrote:
> 
>> Question:
>> How can i set up the setf mapping?
> 
> 
> Just define new methods:
> 
> (defmethod (setf x-coord) (new-value (obj point-3d))
>   (setf (aref (vec obj) 0) new-value))
> 
> etc.
> 
> 
>> And do i need to be
>> concerned that x-coord and y-coord are already defined as
>> generic functions because of my other class definition
>> (state)?
> 
> 
> No. By default, all kinds of methods can be added to generic functions. 
> The generic functions that are implicitly generated by accessors are in 
> no way special in that regard.
> 
> However, it is probably a good idea to document that you intend to 
> define your own methods by defining explicit generic functions like this:
> 
> (defgeneric x-coord (obj))
> (defgeneric (setf x-coord) (new-value obj))
> 
> etc.
> 
> This tells the reader of your program code that you intend to explicitly 
> add methods and don't just want to have the implicitly generated ones. 
> (I have stolen that advice from Scott McKay. ;)
> 
>> Or am i thinking about this completely incorrectly?
> 
> 
> No, I don't think so. But note that you are duplicating things to a 
> certain extent. CLOS implementations usually map slots to arrays on the 
> lowest level, and if they want to conform to the MOP specification they 
> have to. The CLOS MOP defines standard-instance-access as a way to 
> directly access slots by indices. (But this probably doesn't really 
> matter in practice since some MOP implementations don't provide it or 
> deviate from the spec. CLOS implementations usually do a good job at 
> implementing accessor methods efficiently, so efficiency doesn't seem to 
> be a good reason to use standard-instance-access anyway.)
> 
> 
> Pascal
>