From: Daniel J. Yoder
Subject: how do I construct :<<key>> in a macro
Date: 
Message-ID: <pNaZ2.461$tP2.82000@typhoon.austin.rr.com>
Trying to write a code-gen macro around defclass, including generating the
initargs. I cannot for the life of me see how to put a colon character in
front of the keyword I want to use.

To be a little more specific, given the following:

( defmacro attribute ( aname &optional ( init nil ) )
    ( let (( n ( gensym )) ( v ( gensym )) ( k ( gensym )))
            `( let* (( ,n ,aname ) ( ,v ,init ) ( ,k ( make-key ,n )))
                ( list ,n :initarg ,k :initform  ,v :accessor ,n ))))


how to define #'make-key so that what I get is:

( <<key>> :initarg :<<key>> :initform <<val>> :accessor <<key>> )

For example,

( attribute name ) ==> ( name :initarg :name :initform nil :accessor name )

Any ideas? Thanks in advance,

-Dan

From: Rudi Schlatte
Subject: Re: how do I construct :<<key>> in a macro
Date: 
Message-ID: <slrn7jb2jh.qo.rudi@semmel.berg>
In article <···················@typhoon.austin.rr.com>, Daniel J. Yoder wrote:
[...]
>To be a little more specific, given the following:
>
>( defmacro attribute ( aname &optional ( init nil ) )
>    ( let (( n ( gensym )) ( v ( gensym )) ( k ( gensym )))
>            `( let* (( ,n ,aname ) ( ,v ,init ) ( ,k ( make-key ,n )))
>                ( list ,n :initarg ,k :initform  ,v :accessor ,n ))))
>
>how to define #'make-key so that what I get is:
[...]
>( attribute name ) ==> ( name :initarg :name :initform nil :accessor name )

What make-key does, then, is to take a symbol and return a symbol with
the same (symbol-name), but in the keyword package.  

  (intern (symbol-name 'bar) 'keyword)
  => :BAR

The colon is not part of the symbol name, as you seemed to think, 
but is used to separate the package name from the symbol print name. 
When the package name is missing, the symbol is looked up (or added
to) the keyword package.  Any symbol that is added is made a
constant evaluating to itself.  So, the following result T:

  (eq :foo keyword:foo)
  (eq :bar ':bar)

Hope that helps a bit.  

Oh, and out of curiosity:  Is there any perverted way to make a
symbol in KEYWORD _not_ evaluate to itself?  I thought a bit, but
I have to give the symbol name at some point for setf, and
at that point the symbol is interned, exported and made constant
before any further processing.

Rudi
From: Kent M Pitman
Subject: Re: how do I construct :<<key>> in a macro
Date: 
Message-ID: <sfw4slmz32s.fsf@world.std.com>
········@ist.tu-graz.ac.at (Rudi Schlatte) writes:

>   (intern (symbol-name 'bar) 'keyword)
>   => :BAR

Though for efficiency doing
 (defvar *keyword-package* (find-package "KEYWORD"))
and then
 (intern (symbol-name 'bar) *keyword-package*)
is a lot better--saves name lookup on the keyword package every time.
I think we should make *keyword-package* a standard variable in CL,
since it's used a lot.  Most packages are not stored as such because
they might get delete-package'd.  I can't see that happening to the
keyword package and the lisp surviving; if someone *does* do it,
and succeeds, they can surely update a variable.
From: Daniel J. Yoder
Subject: Re: how do I construct :<<key>> in a macro
Date: 
Message-ID: <8VhZ2.499$tP2.87150@typhoon.austin.rr.com>
Thanks everyone who responded.

What I have now is:

( defmacro make-key ( label )
    `( intern ,label :keyword ))

I will take Kent's suggestion, so that this becomes:

( defmacro make-key ( label )
    `( intern ,label *keyword-package* ))

Any reason I particularly ought to use symbol-name? This works without it
...

+d
From: Kent M Pitman
Subject: Re: how do I construct :<<key>> in a macro
Date: 
Message-ID: <sfwbtfunho9.fsf@world.std.com>
"Daniel J. Yoder" <······@tazent.com> writes:

> Thanks everyone who responded.
> 
> What I have now is:
> 
> ( defmacro make-key ( label )
>     `( intern ,label :keyword ))
> 
> I will take Kent's suggestion, so that this becomes:
> 
> ( defmacro make-key ( label )
>     `( intern ,label *keyword-package* ))
> 
> Any reason I particularly ought to use symbol-name? This works without it

It oughtn't.

INTERN only takes a string, not a string designator (i.e., not a symbol
that can be coerced to a string).  Long ago, INTERN used to take symbols
as arguments, but this led to bugs because people confused it with
IMPORT, which takes symbols but does something very different.

If you might get a string, make sure to use either STRING or SYMBOL-NAME
on the argument before giving it to INTERN.  Use STRING if it might also
be a string, use (SYMBOL-NAME x) or (STRING (THE SYMBOL x)) if it might
be a symbol only, since that will be faster in most cases.

Btw, There is no good reasonfor make-key to be a macro.  Making it a macro
makes it impossible to use APPLY or MAPCAR or other higher order functions
becuase #'MAKE-KEY won't work.  You should instead do:

 (defun make-key (label)
   (intern (string label) *keyword-package*))

If it's important to get the extra speed a macro would give (avoiding
the function call), use 
 (declaim (inline make-key))
BEFORE the defun.

Also, my experience is that it's useful to make this function [which
I've written a billion times myself] consider also doing the following
two services:

 (defun make-key (label)
   ;;in case a UI prompted for a string and got no (i.e., an empty) string.  
   (if (equal label "") 
       nil
     ;; in case a UI prompted for a string and got it in odd case
     (intern (string-upcase label) *keyword-package*)))

 (make-key "") => NIL
 (make-key "Fred") => :FRED
 (make-key "fred") => :FRED
 (make-key "FRED") => :FRED

If you don't do these, and you use your definition, you'll get

 (make-key "") => :||
 (make-key "Fred") => :|Fred|
 (make-key "fred") => :|fred|
 (make-key "FRED") => :FRED

For some things, the latter thing is what you want.  For some things, it's
better to do the other.  Mostly you should make the decisions about these
fringe cases consciously in the way that is best for your personal needs
rather than having them surprise you.
From: Barry Margolin
Subject: Re: how do I construct :<<key>> in a macro
Date: 
Message-ID: <nvpZ2.553$jw4.39585@burlma1-snr2>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
>Though for efficiency doing
> (defvar *keyword-package* (find-package "KEYWORD"))
>and then
> (intern (symbol-name 'bar) *keyword-package*)
>is a lot better--saves name lookup on the keyword package every time.

If the use of INTERN in this macro were a performance bottleneck, I would
be very surprised.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.