From: ········@gmail.com
Subject: class creator
Date: 
Message-ID: <1185590197.189886.221820@57g2000hsv.googlegroups.com>
Hi
I'm trying to write a macro that can create a class - something like:

(defmacro class-creator (name)
  `(defclass ,name () ()))

But I want to create several classes by adding different prefixes to
the passed name:

(defmacro class-creator (name)
  "Creates 2 classes called new-name and old-name"
;; with appr gensyms
  (let ((nname (...???)) ;; how to concatenate "new-"
         (oname (...???))) ;; and "old-"
     `(progn
          (defclass ,nname () ())
          (defclass ,oname () ()))))

I tried converting the concatenated string to a symbol (by interning
it) and then using the symbol in the `(defclass...) form. This
resulted in the class being created, but I could not instantiate the
class.

Can anyone let me know any other way to do this?

(The macro originally created several child classes based on the
passed parameters. I've since changed the way these classes are
created, but I'm just curious as to how to do this.)

Thanks
Raja

From: Kent M Pitman
Subject: Re: class creator
Date: 
Message-ID: <utzrp5a4i.fsf@nhplace.com>
········@gmail.com writes:

> Hi
> I'm trying to write a macro that can create a class - something like:
> 
> (defmacro class-creator (name)
>   `(defclass ,name () ()))
> 
> But I want to create several classes by adding different prefixes to
> the passed name:
> 
> (defmacro class-creator (name)
>   "Creates 2 classes called new-name and old-name"
> ;; with appr gensyms
>   (let ((nname (...???)) ;; how to concatenate "new-"
>          (oname (...???))) ;; and "old-"
>      `(progn
>           (defclass ,nname () ())
>           (defclass ,oname () ()))))

I recommend returning `',name from the PROGN here.  That is, don't expose
the internals of your macro by randomly returning one of the two classes
you generate.  Instead return the class name the user gave.  Or else make
a list of the classes by using LIST instead of PROGN.  But it's asymmetric
in an ugly way to do what you've done.
 
> I tried converting the concatenated string to a symbol (by interning
> it) and then using the symbol in the `(defclass...) form. This
> resulted in the class being created, but I could not instantiate the
> class.
> 
> Can anyone let me know any other way to do this?
> 
> (The macro originally created several child classes based on the
> passed parameters. I've since changed the way these classes are
> created, but I'm just curious as to how to do this.)

(INTERN "FOO") => FOO

(INTERN (CONCATENATE 'STRING "FOO" "-" "BAR")) => FOO-BAR

[Intern also takes a package argument, but usually in a macro you'll be ok
 with just accepting the default argument.  There's a huge amount of
 historical debate about that detail, but it's easier for you just to run
 into the problem cases than to try to explain them.  As long as the names
 you're trying to create are not inherited in the current package from 
 another package, you should be fine.]

Does that help?  Some people use (FORMAT NIL "...") to construct such 
strings rather than CONCATENATE.  But the point is that you can manipulate
them with string operations and then call INTERN.

Most string arguments will take symbols--read up on "designators" in
the HyperSpec for details.  If you need to explicitly coerce a symbol,
usually SYMBOL-NAME is the thing you want, though sometimes STRING
will help.  In rare cases, using PRINC-TO-STRING or FORMAT with a NIL
argument is the thing.
From: Daniel Janus
Subject: Re: class creator
Date: 
Message-ID: <slrnfam22s.4q7.przesunmalpe@students.mimuw.edu.pl>
Dnia 28.07.2007 Kent M Pitman <······@nhplace.com> napisa�/a:

> Does that help?  Some people use (FORMAT NIL "...") to construct such 
> strings rather than CONCATENATE.  But the point is that you can manipulate
> them with string operations and then call INTERN.
>
> Most string arguments will take symbols--read up on "designators" in
> the HyperSpec for details.  If you need to explicitly coerce a symbol,
> usually SYMBOL-NAME is the thing you want, though sometimes STRING
> will help.  In rare cases, using PRINC-TO-STRING or FORMAT with a NIL
> argument is the thing.

Note also that SYMBOL-NAME is almost definitely the thing you want if
you want your code to be compatible with "modern" mode of Allegro CL.

-- 
Daniel 'Nathell' Janus, GG #1631668, ············@nathell.korpus.pl
   create_initial_thread(initial_function);
   lose("CATS.  CATS ARE NICE.\n");
      -- Steel Bank Common Lisp, sbcl/runtime/runtime.c:425
From: ········@gmail.com
Subject: Re: class creator
Date: 
Message-ID: <1185630427.724835.195340@g4g2000hsf.googlegroups.com>
> (INTERN "FOO") => FOO
>
> (INTERN (CONCATENATE 'STRING "FOO" "-" "BAR")) => FOO-BAR
>
> [Intern also takes a package argument, but usually in a macro you'll be ok
>  with just accepting the default argument.  There's a huge amount of
>  historical debate about that detail, but it's easier for you just to run
>  into the problem cases than to try to explain them.  As long as the names
>  you're trying to create are not inherited in the current package from
>  another package, you should be fine.]
>
> Does that help?  Some people use (FORMAT NIL "...") to construct such
> strings rather than CONCATENATE.  But the point is that you can manipulate
> them with string operations and then call INTERN.

Thanks - I can make it work now.
I tried this earlier before I posted here, but I didn't know how to
instantiate the new classes:

CL-USER>(classcreator "name")
#<STANDARD-CLASS |new-name|>
CL-USER>(make-instance :new-name)

This threw an error which said that "There is no class named :new-
name".

But if I return the new class names from the progn (a bit like what
you suggested):

CL-USER> (classcreator "name")
(|new-name| |old-name|)
CL-USER> (make-instance (car *))
#<|new-name| {B2B69D9}>

-or-

CL-USER> (classcreator "name")
CL-USER> (defvar newclassname (intern "new-name"))
CL-USER> (make-instance newclassname)

I'm confused as to why the last two methods work and the first one
doesn't. Isn't the new symbol interned in the package :keyword? If so,
shouldn't :new-name be the same as using the return value from the
macro?

I'm guessing it is just way I'm inputting the values into the REPL.

Thanks
Raja
From: Kent M Pitman
Subject: Re: class creator
Date: 
Message-ID: <u1westxkw.fsf@nhplace.com>
········@gmail.com writes:

> I tried this earlier before I posted here, but I didn't know how to
> instantiate the new classes:
> 
> CL-USER>(classcreator "name")
> #<STANDARD-CLASS |new-name|>
> CL-USER>(make-instance :new-name)
> 
> This threw an error which said that "There is no class named :new-
> name".

:new-name is the keyword package.  If you think you want to make a symbol
in that package, use (INTERN "NEW-NAME" "KEYWORD").  I don't recommend
diong this for reasons explained below.

Please note:  INTERN is case-sensitive.  "new-name" and "NEW-name" and
"NEW-NAME" all different.

If you're going to use a prefix string, you probably want use uppercase.
That is (intern (concatenate 'string "NEW-" (symbol-name x))) not
(intern (concatenate 'string "new-" (symbol-name x))) since
the former, given a symbol FOO will return "NEW-FOO" and the latter will
return "new-FOO".

The reader will do case-translating so when you write 'foo you are
really writing 'FOO.  There are various ways to use lowercase symbols,
each with its benefits and weaknesses (which I'll let others explain).
What you should know is is that Common Lisp is case-sensitive
internally, stores all its default symbols in uppercase, and
case-translates input to match.

> But if I return the new class names from the progn (a bit like what
> you suggested):
> 
> CL-USER> (classcreator "name")
> (|new-name| |old-name|)
> CL-USER> (make-instance (car *))
> #<|new-name| {B2B69D9}>
> 
> -or-
> 
> CL-USER> (classcreator "name")
> CL-USER> (defvar newclassname (intern "new-name"))
> CL-USER> (make-instance newclassname)
> 
> I'm confused as to why the last two methods work and the first one
> doesn't. Isn't the new symbol interned in the package :keyword? If so,
> shouldn't :new-name be the same as using the return value from the
> macro?
> 
> I'm guessing it is just way I'm inputting the values into the REPL.

I think it's the casification problem that's really getting you.

The keyword thing is hopefully not your intent, just a confusion you have?

I strongly recommend not trying to put the info in the keyword package.
The keyword package is effectively a flat namespace, easily accessible
to all packages, but not for anything that is user-extensible since by
its nature it's shared and if you were to define a class name in it, it
would clobber any name defined by someone else.  (See the restrictions
on the CL package and apply them to the KEYWORD package, too, if there
is not a similar restriction on keyword just for good measure... I don't
recall if there is an explicit prohibition, but it makes sense to assume
one due to reasoning akin to the Prisoner's Dilemma.)

Does that help?
From: ········@gmail.com
Subject: Re: class creator
Date: 
Message-ID: <1185634584.329090.208540@k79g2000hse.googlegroups.com>
> Please note:  INTERN is case-sensitive.  "new-name" and "NEW-name" and
> "NEW-NAME" all different.
>
> If you're going to use a prefix string, you probably want use uppercase.
> That is (intern (concatenate 'string "NEW-" (symbol-name x))) not
> (intern (concatenate 'string "new-" (symbol-name x))) since
> the former, given a symbol FOO will return "NEW-FOO" and the latter will
> return "new-FOO".

Yes - it was a problem with the case.

> The keyword thing is hopefully not your intent, just a confusion you have?
>
Yes - eventually I was going to move everything to my package. But
again, I moved away from this method of creating classes to explicitly
getting the names from the user.


Thanks
Raja
From: Rainer Joswig
Subject: Re: class creator
Date: 
Message-ID: <joswig-28FFE4.17512129072007@news-europe.giganews.com>
In article <························@g4g2000hsf.googlegroups.com>,
 ········@gmail.com wrote:

> > (INTERN "FOO") => FOO
> >
> > (INTERN (CONCATENATE 'STRING "FOO" "-" "BAR")) => FOO-BAR
> >
> > [Intern also takes a package argument, but usually in a macro you'll be ok
> >  with just accepting the default argument.  There's a huge amount of
> >  historical debate about that detail, but it's easier for you just to run
> >  into the problem cases than to try to explain them.  As long as the names
> >  you're trying to create are not inherited in the current package from
> >  another package, you should be fine.]
> >
> > Does that help?  Some people use (FORMAT NIL "...") to construct such
> > strings rather than CONCATENATE.  But the point is that you can manipulate
> > them with string operations and then call INTERN.
> 
> Thanks - I can make it work now.
> I tried this earlier before I posted here, but I didn't know how to
> instantiate the new classes:
> 
> CL-USER>(classcreator "name")
> #<STANDARD-CLASS |new-name|>
> CL-USER>(make-instance :new-name)
> 
> This threw an error which said that "There is no class named :new-
> name".
> 
> But if I return the new class names from the progn (a bit like what
> you suggested):
> 
> CL-USER> (classcreator "name")
> (|new-name| |old-name|)
> CL-USER> (make-instance (car *))
> #<|new-name| {B2B69D9}>
> 
> -or-
> 
> CL-USER> (classcreator "name")
> CL-USER> (defvar newclassname (intern "new-name"))
> CL-USER> (make-instance newclassname)
> 
> I'm confused as to why the last two methods work and the first one
> doesn't. Isn't the new symbol interned in the package :keyword? If so,
> shouldn't :new-name be the same as using the return value from the
> macro?
> 
> I'm guessing it is just way I'm inputting the values into the REPL.
> 
> Thanks
> Raja

? (defclass foo () ())
#<STANDARD-CLASS FOO>
? (class-name *)
FOO
? (symbol-name *)
"FOO"

Symbols are by default read as uppercase.

If you create a class with a lower case name ("new-name")
then you need to use a lower case symbol:   :|new-name|

-- 
http://lispm.dyndns.org