From: Leslie P. Polzer
Subject: Better solution for compile-time generated accessor
Date: 
Message-ID: <647f0b6b-7127-41eb-868c-aad035d70040@34g2000hsf.googlegroups.com>
I have a list of symbols in *PLAYER-SLOTS*, and would like to define
custom accessors for each one of them.

The following does what I want:

(defmacro make-effective-attribute-axr (attr)
  `(defmethod ,attr ((player player))
     (+ (slot-value player ',attr)
        (total-attribute-modifier player ',attr))))

(defmacro make-effective-attribute-axrs ()
  `(progn
     ,@(iter (for attr in *player-attributes*)
             (collecting `(make-effective-attribute-axr ,attr)))))

(make-effective-attribute-axrs)


But looks and feels clumsy.

Is there a better way?

Thanks,

  Leslie

From: Rainer Joswig
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <joswig-946E86.13175406062008@news-europe.giganews.com>
In article 
<····································@34g2000hsf.googlegroups.com>,
 "Leslie P. Polzer" <·············@gmx.net> wrote:

> I have a list of symbols in *PLAYER-SLOTS*, and would like to define
> custom accessors for each one of them.
> 
> The following does what I want:
> 
> (defmacro make-effective-attribute-axr (attr)
>   `(defmethod ,attr ((player player))
>      (+ (slot-value player ',attr)
>         (total-attribute-modifier player ',attr))))
> 
> (defmacro make-effective-attribute-axrs ()
>   `(progn
>      ,@(iter (for attr in *player-attributes*)
>              (collecting `(make-effective-attribute-axr ,attr)))))
> 
> (make-effective-attribute-axrs)
> 
> 
> But looks and feels clumsy.
> 
> Is there a better way?

Yes, less macros.

If you name anything 'make-something' then it is
a function. If you name something DEFsomething, then
it is a macro.

(defun make-effective-attribute-axr (attr)
  `(defmethod ,attr ((player player))
     (+ (slot-value player ',attr)
        (total-attribute-modifier player ',attr))))

(defun make-effective-attribute-axrs ()
  `(progn
      ,@(mapcar #'make-effective-attribute-axr
                *player-attributes*)))

Whenever you want to create more than trivial code, write functions
to do it. Those are easier to write and test.

(defmacro define-effective-attribute-axrs ()
   (make-effective-attribute-axrs))


CL-USER 26 > (setf *player-attributes* '(size age))
(SIZE AGE)

CL-USER 27 > (make-effective-attribute-axrs)
(PROGN (DEFMETHOD SIZE ((PLAYER PLAYER)) (+ (SLOT-VALUE PLAYER (QUOTE SIZE)) (TOTAL-ATTRIBUTE-MODIFIER PLAYER (QUOTE SIZE)))) (DEFMETHOD AGE ((PLAYER PLAYER)) (+ (SLOT-VALUE PLAYER (QUOTE AGE)) (TOTAL-ATTRIBUTE-MODIFIER PLAYER (QUOTE AGE)))))

CL-USER 28 > (pprint *)

(PROGN
  (DEFMETHOD SIZE ((PLAYER PLAYER)) (+ (SLOT-VALUE PLAYER 'SIZE) (TOTAL-ATTRIBUTE-MODIFIER PLAYER 'SIZE)))
  (DEFMETHOD AGE ((PLAYER PLAYER)) (+ (SLOT-VALUE PLAYER 'AGE) (TOTAL-ATTRIBUTE-MODIFIER PLAYER 'AGE))))


Other ways would be to use method combinations:

(defclass player () ((size :accessor size)))

(defmethod size :around ((player player))
   (+ (get-next-method) (TOTAL-ATTRIBUTE-MODIFIER PLAYER 'SIZE)))

Or even use a different method combination like '+' :

(defclass total-mixin ()
   (total-size))

(defclass player (total-mixin)
   (size))

(defgeneric size (player) (:method-combination +))
(defmethod size + ((thing total-mixin)) (slot-value thing 'total-size))
(defmethod size + ((player player)) (slot-value thing 'size))

Now (size *my-player)  will return the sum of the results of all applicable methods called on *my-player*.

> 
> Thanks,
> 
>   Leslie

-- 
http://lispm.dyndns.org/
From: Leslie P. Polzer
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <19525556-a004-4a04-bd27-6c94d5957e46@f63g2000hsf.googlegroups.com>
Rainer,

that was a lot of great input. Thanks!
From: Madhu
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <m3prquiyeq.fsf@meer.net>
* "Leslie P. Polzer" <····································@34g2000hsf.googlegroups.com> :
Wrote on Fri, 6 Jun 2008 03:44:08 -0700 (PDT):

| I have a list of symbols in *PLAYER-SLOTS*, and would like to define
| custom accessors for each one of them.
|
| (defmacro make-effective-attribute-axr (attr)
|   `(defmethod ,attr ((player player))
|      (+ (slot-value player ',attr)
|         (total-attribute-modifier player ',attr))))
|
| (defmacro make-effective-attribute-axrs ()
|   `(progn
|      ,@(iter (for attr in *player-attributes*)
|              (collecting `(make-effective-attribute-axr ,attr)))))
|
| (make-effective-attribute-axrs)
|
| But looks and feels clumsy.

[Without mentioning ITER]
Is there any compelling reason to turn all symbols in
*PLAYER-ATTRIBUTES* into generic functions?

I'm not sure why you call these methods `accessors', do they have a
corresponding setf component?

If the answer to both is No, I'd be inclined to go with a simple

(defun access-attr (player attr) 
   (+ (slot-value player 'attr) (total-attribute-modifier player attr)))

until some other requirement came up.
--
Madhu
From: Alex Mizrahi
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <484955ff$0$90267$14726298@news.sunsite.dk>
(message (Hello 'Leslie)
(you :wrote  :on '(Fri, 6 Jun 2008 03:44:08 -0700 (PDT)))
(

 LPP> I have a list of symbols in *PLAYER-SLOTS*, and would like to define
 LPP> custom accessors for each one of them.

 LPP> The following does what I want:

 LPP> (defmacro make-effective-attribute-axr (attr)
 LPP>   `(defmethod ,attr ((player player))
 LPP>      (+ (slot-value player ',attr)
 LPP>         (total-attribute-modifier player ',attr))))

 LPP> (defmacro make-effective-attribute-axrs ()
 LPP>   `(progn
 LPP>      ,@(iter (for attr in *player-attributes*)
 LPP>              (collecting `(make-effective-attribute-axr ,attr)))))

 LPP> (make-effective-attribute-axrs)

 LPP> But looks and feels clumsy.

 LPP> Is there a better way?

if you do this just once, you can use #. for read time evaluation instead of 
macros:

#.(cons 'progn
        (loop for attr in *player-attributes*
           collect `(defmethod ,attr ... 
From: Leslie P. Polzer
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <c5122089-be16-4d51-81fc-d6bdf1ad5cc0@y21g2000hsf.googlegroups.com>
> if you do this just once, you can use #. for read time evaluation instead of
> macros:
>
> #.(cons 'progn
>         (loop for attr in *player-attributes*
>            collect `(defmethod ,attr ...

Gotta slap my head, I was so close and yet quite wrong with

#.(apply #'progn
        (loop for attr in *player-attributes*
           collect `(defmethod ,attr ...

Thanks.
From: Thomas A. Russ
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <ymilk1ebi16.fsf@blackcat.isi.edu>
"Leslie P. Polzer" <·············@gmx.net> writes:

> Gotta slap my head, I was so close and yet quite wrong with
> 
> #.(apply #'progn
>         (loop for attr in *player-attributes*
>            collect `(defmethod ,attr ...

Um, you can't apply PROGN.  At least not portably, since it is a special
form and not a regular function.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Leslie P. Polzer
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <98631079-1582-496e-a715-4d9ab1b18388@t54g2000hsg.googlegroups.com>
> Um, you can't apply PROGN.  At least not portably, since it is a special
> form and not a regular function.

Yes, that was my second (and smaller) mistake, the first being
ignorant about
the list-generating nature of #.

  Leslie
From: Pascal J. Bourguignon
Subject: Re: Better solution for compile-time generated accessor
Date: 
Message-ID: <7c1w34w6km.fsf@pbourguignon.anevia.com>
"Leslie P. Polzer" <·············@gmx.net> writes:

>> Um, you can't apply PROGN. �At least not portably, since it is a special
>> form and not a regular function.
>
> Yes, that was my second (and smaller) mistake, the first being
> ignorant about
> the list-generating nature of #.

#. doesn't generate lists:

C/USER[57]> (quote (+ 2 3))
(+ 2 3)
C/USER[58]> (quote #.(+ 2 3))
5

When the reader reads #., it reads the expression that follows,
evaluates it, and returns its result.  All depends on that
expression. If <expression> evaluates to a list, then reading
#.<expression> will read this list, but if it evaluates to an atom, then
we'll get that atom.

-- 
__Pascal Bourguignon__