From: Rene de Visser
Subject: Setf and reading function: How to avoid duplication of code?
Date: 
Message-ID: <a128it$itt$1@news1.wdf.sap-ag.de>
How can the following be improved?

One option would be to use a macro to generate both classify and (setf
classify), but this seems like unnessary complexitiy.
Ideally I would like to just write (setf classify) and somehow derive
classify  from it.

I have several times written read and set (setf) routines and then had the
problem of having most of the code duplicated between the reading and
setting functions. Is there a better way?

(defstruct mystructure
 var1
 var2
 var3
 var4)

(defun (setf classify) (value structure color)
 (ecase color
  (#\B (setf (mystructure-var1 structure) value))
  (#\W (setf (mystructure-var2 structure) value))
  ('(#\G #\R) (setf (mystructure-var3 structure) value))
  (t (setf (mystructure-var4 structure) value))))

(defun classify (structure color)
 (ecase color
  (#\B (mystructure-var1 structure))
  (#\W (mystructure-var2 structure))
  ('(#\G #\R) (mystructure-var3 structure))
  (t (mystructure-var4 structure))))

(let ((structure (make-mystructure)))
 (setf (classify structure #\B ) 100)
 (classify structure #\B))

From: Chris Riesbeck
Subject: Re: Setf and reading function: How to avoid duplication of code?
Date: 
Message-ID: <riesbeck-FE10BE.17382903012002@news.it.nwu.edu>
In article <············@news1.wdf.sap-ag.de>, "Rene de Visser" 
<··············@hotmail.de> wrote:

>How can the following be improved?
>
>(defun (setf classify) (value structure color)
> (ecase color
>  (#\B (setf (mystructure-var1 structure) value))
>  (#\W (setf (mystructure-var2 structure) value))
>  ('(#\G #\R) (setf (mystructure-var3 structure) value))

I don't think you want the quote here.

>  (t (setf (mystructure-var4 structure) value))))

This is illegal. ECASE doesn't permit else clauses. Use CASE.

>(defun classify (structure color)
> (ecase color
>  (#\B (mystructure-var1 structure))
>  (#\W (mystructure-var2 structure))
>  ('(#\G #\R) (mystructure-var3 structure))
>  (t (mystructure-var4 structure))))
>
>(let ((structure (make-mystructure)))
> (setf (classify structure #\B ) 100)
> (classify structure #\B))

Do you have a reason for a structure? Or is it the form of
the example you need to support. If the latter, I'd do this:

(defmacro classify (data color)
  `(aref ,data (get-color-index ,color)))

(defun get-color-index (color)
  (case color
    (#\B 0)
    (#\W 1)
    ((#\G #\R) 2)
    (t 3)))
  
(let ((data (make-array 4)))
 (setf (classify data #\B ) 100)
 (classify data #\B))
From: Barry Margolin
Subject: Re: Setf and reading function: How to avoid duplication of code?
Date: 
Message-ID: <ui7Z7.2$Tr2.20883@burlma1-snr2>
In article <············@news1.wdf.sap-ag.de>,
Rene de Visser <··············@hotmail.de> wrote:
>How can the following be improved?
>
>One option would be to use a macro to generate both classify and (setf
>classify), but this seems like unnessary complexitiy.
>Ideally I would like to just write (setf classify) and somehow derive
>classify  from it.

Lisp isn't a logic language, it doesn't automatically work out derivations
like this.  SETF isn't a magic bullet, it's just a common notation for
assignment operators -- you still have to tell the system how to perform
the assignment.

>I have several times written read and set (setf) routines and then had the
>problem of having most of the code duplicated between the reading and
>setting functions. Is there a better way?
>
>(defstruct mystructure
> var1
> var2
> var3
> var4)
>
>(defun (setf classify) (value structure color)
> (ecase color
>  (#\B (setf (mystructure-var1 structure) value))
>  (#\W (setf (mystructure-var2 structure) value))
>  ('(#\G #\R) (setf (mystructure-var3 structure) value))
>  (t (setf (mystructure-var4 structure) value))))
>
>(defun classify (structure color)
> (ecase color
>  (#\B (mystructure-var1 structure))
>  (#\W (mystructure-var2 structure))
>  ('(#\G #\R) (mystructure-var3 structure))
>  (t (mystructure-var4 structure))))

(defconstant +mystructure-slot-alist+
  `((var1 ,#'mystructure-var1 #'(setf mystructure-var1))
    (var2 ,#'mystructure-var2 #'(setf mystructure-var2))
    (var3 ,#'mystructure-var3 #'(setf mystructure-var3))
    (var4 ,#'mystructure-var4 #'(setf mystructure-var4)))
   "Alist mapping MYSTRUCTURE slot names to getter and setter")

(defun color-to-slot (color)
  (case color
    (#\B 'var1)
    (#\W 'var2)
    ((#\G #\R) 'var3)
    (t 'var4)))

(defun mystructure-reader (color)
  (second (assoc (color-to-slot color) +mystructure-slot-alist+)))

(defun mystructure-setter (color)
  (third (assoc (color-to-slot color) +mystructure-slot-alist+)))

(defun (setf classify) (value structure color)
  (apply (mystructure-setter color) value structure))
  
(defun classify (structure color)
  (apply (mystructure-reader color) structure))

All that alist stuff could be done away with if you used a class instead of
a structure.  Then you could do:

(defun mystructure-reader (color)
  (fdefinition (color-to-slot color)))

(defun mystructure-setter (color)
  (fdefinition `(setf ,(color-to-slot color))))

Or you could use SLOT-VALUE instead of the generic functions to access the
slots:

(defun (setf classify) (value structure color)
  (setf (slot-value structure (color-to-slot color)) value)

(defun classify (structure color)
  (slot-value structure (color-to-slot color)))

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.