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
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/
* "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
(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 ...
> 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
> 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
"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__