Search code examples
ooplispcommon-lispclossetf

Why aren't generic functions the same as accessor functions lisp


From the things I have read I understand that Accessor functions in CLOS allows for the programmer to get and set variables and it generates a generic function of the name that was give in to the accessor to which you need to define different methods.But I what I want to know is why Don't generic functions work the same way as the accessor functions?

for example

 (defclass animal ()
       ((sound
         :initarg :sound
         :initform "no sound"
         :accessor make-sound)))

I can just define

(defmethod (setf make-sound) ((the-animal animal) value)
       (setf (slot-value the-animal 'sound) value))

but if i were to take the accessor away and add in

(defgeneric (setf make-sound) (the-animal value))

then I get an error when after executing the following code.

(setf (make-sound dog) "bark")

unless I redefine the generic function and method as the following

(defgeneric (setf make-sound) (value the-animal))

 (defmethod (setf make-sound) (value (the-animal animal))
   (setf (slot-value the-animal 'sound) value))

or execute

(setf (make-sound "bark") dog) ;this also works with the accessor

My question is why is this happening?Why can't I achieve the same result with generic functions?


Solution

  • A defmethod form creates a generic function if there isn't one.

    CL-USER 7 > (defclass animal ()
                  ((sound
                    :initarg :sound
                    :initform "no sound")))
    #<STANDARD-CLASS ANIMAL 40200ED09B>
    

    Remember: the new value comes first in a SETF function. That's defined by the Common Lisp standard.

    CL-USER 8 > (defmethod (setf make-sound) (value (the-animal animal))
                  (setf (slot-value the-animal 'sound) value))
    #<STANDARD-METHOD (SETF MAKE-SOUND) NIL (T ANIMAL) 40200F098B>
    
    CL-USER 9 > (let ((dog (make-instance 'animal)))
                  (setf (make-sound dog) "bark")
                  dog)
    #<ANIMAL 402002187B>
    
    CL-USER 10 > (slot-value * 'sound)
    "bark"
    

    Seems to work.

    In defclass the :accessor slot option defines that it defines a reader method and also a corresponding setf method with the correct parameter list: new value first, then the instance of that class.