From: Johan Parin
Subject: Is eval appropriate here?
Date: 
Message-ID: <kv4tdb5g1c.fsf@uab.ericsson.se>
Hello,

I would like some advice on a style issue.  I have a situation where I
want to create a lot of classes. I have a list like this:

(defconstant *instructions*
  '(
    (<instruction> <opcode> ...)
    ...))

From this I want to generate classes:

(defclass a-instruction (instruction)
  ((name :allocation :class :initform :a)
   (opcode :allocation :class :initform <a-opcode>)
   ...))

etc.

The only thing I have come up with uses eval:

(dolist (inst-info *instructions*)
  (let ((name (symbol-name (car inst-info)))
        (opcode (nth 1 inst-info))
        ...)
    (eval `(defclass ,(intern (concatenate 'string name "-INSTRUCTION"))
            (instruction)
            ((name :allocation :class :initform ,(car inst-info))
             (opcode :allocaton :class :initform ,opcode)
             ...)))))

This seems to work fine. However I was wondering if this is a
situation where eval is appropriate or if there is a `cleaner'
solution. The problem is that defclass does not evaluate its first
argument. Evaluating the intern within a sharp-dot reader macro will
not work either because the symbols inst-info etc will not be
visible.


---
Johan Parin
Ericsson AXE Research & Development, Stockholm, SWEDEN
From: Barry Margolin
Subject: Re: Is eval appropriate here?
Date: 
Message-ID: <5iqvq2$qj4@pasilla.bbnplanet.com>
In article <··············@uab.ericsson.se>,
Johan Parin  <······@uab.ericsson.se> wrote:
>The only thing I have come up with uses eval:
>
>(dolist (inst-info *instructions*)
>  (let ((name (symbol-name (car inst-info)))
>        (opcode (nth 1 inst-info))
>        ...)
>    (eval `(defclass ,(intern (concatenate 'string name "-INSTRUCTION"))
>            (instruction)
>            ((name :allocation :class :initform ,(car inst-info))
>             (opcode :allocaton :class :initform ,opcode)
>             ...)))))
>
>This seems to work fine. However I was wondering if this is a
>situation where eval is appropriate or if there is a `cleaner'
>solution.

If you're restricting yourself to operators defined in ANSI Common Lisp or
CLtL2, then EVAL is the only way to do it.

The way to do it without EVAL is by making use of the CLOS "Meta-Object
Protocol".  You could then write something like:

(make-instance 'class :name (intern ...) ...)

The MOP is not officially standardized, but many implementations conform
pretty closely to what's described in the book "The Art of the Meta-Object
Protocol".

IMHO, for an application like yours, EVAL is a fine solution unless you
were hoping to be able to run your code through a tree-shaker.
-- 
Barry Margolin
BBN Corporation, Cambridge, MA
······@bbnplanet.com
(BBN customers, call (800) 632-7638 option 1 for support)