The other day I found myself wanting to define classes that had
computed names. When I attempted to define a macro to do this I ran
into difficulties. It seemed that I needed to get from the name, a
string, to a symbol for the sake of defclass. The thing I got to work
was weaving intern into the mix like [simplified]:
(defmacro make-cls (name)
`(defclass ,(intern name) () () ))
This of course doesn't work for general cases. For instance,
(let ((x "MYCLASS"))
(make-cls x))
errors out saying x is not a string as no evaluation happens. Putting
a "," before name causes gives a comma not in backquote error. So how
would I do this more generally? Probably there is something simple I
am not seeing as I am a youngling when it comes to macros.
Thanks for any help.
- s
From: KenNULLSPAMTilton
Subject: Re: defining a class in a macro
Date:
Message-ID: <HIwOf.166$_g6.69@fe12.lga>
samantha wrote:
> The other day I found myself wanting to define classes that had
> computed names.
That sounds wrong.
> When I attempted to define a macro to do this I ran
> into difficulties. It seemed that I needed to get from the name, a
> string, to a symbol for the sake of defclass. The thing I got to work
> was weaving intern into the mix like [simplified]:
>
> (defmacro make-cls (name)
> `(defclass ,(intern name) () () ))
>
> This of course doesn't work for general cases. For instance,
>
> (let ((x "MYCLASS"))
> (make-cls x))
>
> errors out saying x is not a string as no evaluation happens. Putting
> a "," before name causes gives a comma not in backquote error. So how
> would I do this more generally? Probably there is something simple I
> am not seeing as I am a youngling when it comes to macros.
Actually, you see it, you just don't realize that you are right: you
cannot have it both ways. A macro arg is either evaluated or not,
because if you try for both, how is the macro to know what is meant in
any given case?* Your desire for "more generally" asks too much. With
macros, it is understood that any given argument is or is not evaluated.
In the last case, you want x in (make-cls x) evaluated. ie, "The name is
'MYCLASS', not 'x'!!!!". Fine. But in your actual macro code you are
evaluating the argument name.
Since you want computed names, one might guess you want the macro to
evaluate its class-name arg. More likely (winging it here) you want to
embed the class-name calculation within the macro computation that
produces the final form. Most likely, as guessed above, you should not
be doing this at all. So...
Why are you computing class names?
kt
* There are games you can play. i do that with a debug macro, that looks
at the first argument and expands differently if it is a string, nil, or
anything else. But, hey, it is a /debug/ macro, it is bound to be a hack. :)
From: Bill Atkins
Subject: Re: defining a class in a macro
Date:
Message-ID: <87lkvp5n7x.fsf@rpi.edu>
"samantha" <········@gmail.com> writes:
> The other day I found myself wanting to define classes that had
> computed names. When I attempted to define a macro to do this I ran
> into difficulties. It seemed that I needed to get from the name, a
> string, to a symbol for the sake of defclass. The thing I got to work
> was weaving intern into the mix like [simplified]:
>
> (defmacro make-cls (name)
> `(defclass ,(intern name) () () ))
>
> This of course doesn't work for general cases. For instance,
>
> (let ((x "MYCLASS"))
> (make-cls x))
>
> errors out saying x is not a string as no evaluation happens. Putting
> a "," before name causes gives a comma not in backquote error. So how
> would I do this more generally? Probably there is something simple I
> am not seeing as I am a youngling when it comes to macros.
>
> Thanks for any help.
>
> - s
As others have mentioned, the problem is that make-cls is passed the
literal symbol X when it is expanded, not the value it is assigned at
runtime.
To see this, you can macro-expand the form (make-cls x), which will
give you:
(defclass x () () ))
So Lisp dutifully creates a class named X, since macros are expanded
well before the (let ... ) form is actually evaluated.
HTH,
Bill Atkins
"samantha" <········@gmail.com> writes:
> The other day I found myself wanting to define classes that had
> computed names. When I attempted to define a macro to do this I ran
> into difficulties. It seemed that I needed to get from the name, a
> string, to a symbol for the sake of defclass. The thing I got to work
> was weaving intern into the mix like [simplified]:
>
> (defmacro make-cls (name)
> `(defclass ,(intern name) () () ))
>
> This of course doesn't work for general cases. For instance,
>
> (let ((x "MYCLASS"))
> (make-cls x))
>
> errors out saying x is not a string as no evaluation happens. Putting
> a "," before name causes gives a comma not in backquote error.
Macros don't get their arguments evaluated. Functions do. If you
want to compute (at run-time) the argument, then you don't want a
macro, you want a function!
> So how
> would I do this more generally? Probably there is something simple I
> am not seeing as I am a youngling when it comes to macros.
(defun make-class (name) (eval `(defclass ,(intern name) () ())))
Otherwise, use MOP.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
"samantha" <········@gmail.com> writes:
> (defmacro make-cls (name)
> `(defclass ,(intern name) () () ))
>
> This of course doesn't work for general cases. For instance,
>
> (let ((x "MYCLASS"))
> (make-cls x))
Is the string "MYCLASS" known at read time or compile time, or
only later (load time or run time)? If later, then a mere macro
will not suffice; you'll need EVAL or the MOP (e.g. ENSURE-CLASS).
If only the name of the class varies, then you might also be able
to do something like:
(defmacro make-cls (name-form)
(let ((initial-name (gensym)))
`(progn
(defclass ,initial-name () ())
(let ((name ,name-form)
(class (find-class ',initial-name)))
(setf (find-class name) class
(find-class ',initial-name) nil
(class-name class) name)))))
However, I'm not sure this wouldn't violate 3.2.2.3 "Semantic Constraints".
On 5 Mar 2006 03:52:10 -0800, "samantha" <········@gmail.com> wrote:
>
> Thanks to all. This is about what I figured. MOP book came off my
> shelf an hour before I posted. :-)
>
> - samantha
You've probably moved way past this issue in your
work, but let me just recommend Pascal Costanza's
Closer to MOP project:
http://common-lisp.net/project/closer/closer-mop.html
I just started using it in my code, not only to generate
classes based on computed names but also to add methods
specializing on instances of those generated classes.
It works really well (I've only tested on CLISP and
LW, but he's got support in there for several other
vendors as well).
--
Jack Unrue