From: Glenn Burnside
Subject: Newbie macro question
Date: 
Message-ID: <uhenqpe6llpodf@corp.supernews.com>
I've gotten stumped on a macro I'm trying to write.  I'm open to any
suggestions, as I could be entirely off base with my approach.  I'm trying
to write a macro that acts like format, but generates a string when it is
evaluated, rather than at run-time.  The best I've come up with is:

(defmacro build-string (control &rest args) (eval `(format nil ,control
,@args)))

But everything I've read says - don't use eval, you don't need it, that's
what macros are for, etc.  Is there a better way to do this?

Thanks,
    Glenn Burnside

From: Barry Margolin
Subject: Re: Newbie macro question
Date: 
Message-ID: <7jJR8.17$317.1997@paloalto-snr1.gtei.net>
In article <··············@corp.supernews.com>,
Glenn Burnside <··············@ni.com> wrote:
>I've gotten stumped on a macro I'm trying to write.  I'm open to any
>suggestions, as I could be entirely off base with my approach.  I'm trying
>to write a macro that acts like format, but generates a string when it is
>evaluated, rather than at run-time. The best I've come up with is:
>
>(defmacro build-string (control &rest args) (eval `(format nil ,control
>,@args)))
>
>But everything I've read says - don't use eval, you don't need it, that's
>what macros are for, etc.  Is there a better way to do this?

Just call FORMAT and return the string:

(defmacro build-string (control &rest args)
  (apply #'format nil control args))

In either implementation, be aware that you can't reference any local
variables, since they don't exist until run-time.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, 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.
From: Glenn Burnside
Subject: Re: Newbie macro question
Date: 
Message-ID: <uhep3a6qvqjsc5@corp.supernews.com>
"Barry Margolin" <······@genuity.net> wrote in message
······················@paloalto-snr1.gtei.net...
> In article <··············@corp.supernews.com>,
> Glenn Burnside <··············@ni.com> wrote:
> >I've gotten stumped on a macro I'm trying to write.  I'm open to any
> >suggestions, as I could be entirely off base with my approach.  I'm
trying
> >to write a macro that acts like format, but generates a string when it is
> >evaluated, rather than at run-time. The best I've come up with is:
> >
> >(defmacro build-string (control &rest args) (eval `(format nil ,control
> >,@args)))
> >
> >But everything I've read says - don't use eval, you don't need it, that's
> >what macros are for, etc.  Is there a better way to do this?
>
> Just call FORMAT and return the string:
>
> (defmacro build-string (control &rest args)
>   (apply #'format nil control args))
>
> In either implementation, be aware that you can't reference any local
> variables, since they don't exist until run-time.
>
> --
> Barry Margolin, ······@genuity.net
> Genuity, Woburn, 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.

You know, I tried exactly that, but I found there's a difference in behavior
between your solution and mine:
In your solution, the macro arguments are not evaluated before they are
passed to format.  In mine, they are.  So, for below,

(defvar four 4)
(build-string "~A" four)

your solution creates the string "FOUR" and mine creates "4".

For my purposes, I'm looking for the behavior of my solution.

Glenn Burnside.
From: Nils Goesche
Subject: Re: Newbie macro question
Date: 
Message-ID: <lk7kkoijmh.fsf@pc022.bln.elmeg.de>
"Glenn Burnside" <··············@ni.com> writes:

> "Barry Margolin" <······@genuity.net> wrote in message
> ······················@paloalto-snr1.gtei.net...
> > In article <··············@corp.supernews.com>,
> > Glenn Burnside <··············@ni.com> wrote:
> > >I've gotten stumped on a macro I'm trying to write.  I'm open to any
> > >suggestions, as I could be entirely off base with my approach.  I'm
> trying
> > >to write a macro that acts like format, but generates a string when it is
> > >evaluated, rather than at run-time. The best I've come up with is:
> > >
> > >(defmacro build-string (control &rest args) (eval `(format nil ,control
> > >,@args)))
> > >
> > >But everything I've read says - don't use eval, you don't need it, that's
> > >what macros are for, etc.  Is there a better way to do this?
> >
> > Just call FORMAT and return the string:
> >
> > (defmacro build-string (control &rest args)
> >   (apply #'format nil control args))
> >
> > In either implementation, be aware that you can't reference any local
> > variables, since they don't exist until run-time.

> You know, I tried exactly that, but I found there's a difference in behavior
> between your solution and mine:
> In your solution, the macro arguments are not evaluated before they are
> passed to format.  In mine, they are.  So, for below,
> 
> (defvar four 4)
> (build-string "~A" four)
> 
> your solution creates the string "FOUR" and mine creates "4".
> 
> For my purposes, I'm looking for the behavior of my solution.

Well, if your macro definition does exactly what you're looking for,
good for you :-)  However, I think it is an extremely weird macro, and
it would never occur to me to write such a thing.  For instance,

(defvar four 4)
(build-string "~A" four)

in the same source file will /not/ compile unless you have defined
FOUR somewhere else before calling COMPILE-FILE...

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9
From: Glenn Burnside
Subject: Re: Newbie macro question
Date: 
Message-ID: <uhestct1cp1ub2@corp.supernews.com>
"Nils Goesche" <······@cartan.de> wrote in message
···················@pc022.bln.elmeg.de...
> "Glenn Burnside" <··············@ni.com> writes:
>
> > "Barry Margolin" <······@genuity.net> wrote in message
> > ······················@paloalto-snr1.gtei.net...
> > > In article <··············@corp.supernews.com>,
> > > Glenn Burnside <··············@ni.com> wrote:
> > > >I've gotten stumped on a macro I'm trying to write.  I'm open to any
> > > >suggestions, as I could be entirely off base with my approach.  I'm
> > trying
> > > >to write a macro that acts like format, but generates a string when
it is
> > > >evaluated, rather than at run-time. The best I've come up with is:
> > > >
> > > >(defmacro build-string (control &rest args) (eval `(format nil
,control
> > > >,@args)))
> > > >
> > > >But everything I've read says - don't use eval, you don't need it,
that's
> > > >what macros are for, etc.  Is there a better way to do this?
> > >
> > > Just call FORMAT and return the string:
> > >
> > > (defmacro build-string (control &rest args)
> > >   (apply #'format nil control args))
> > >
> > > In either implementation, be aware that you can't reference any local
> > > variables, since they don't exist until run-time.
>
> > You know, I tried exactly that, but I found there's a difference in
behavior
> > between your solution and mine:
> > In your solution, the macro arguments are not evaluated before they are
> > passed to format.  In mine, they are.  So, for below,
> >
> > (defvar four 4)
> > (build-string "~A" four)
> >
> > your solution creates the string "FOUR" and mine creates "4".
> >
> > For my purposes, I'm looking for the behavior of my solution.
>
> Well, if your macro definition does exactly what you're looking for,
> good for you :-)  However, I think it is an extremely weird macro, and
> it would never occur to me to write such a thing.  For instance,
>
> (defvar four 4)
> (build-string "~A" four)
>
> in the same source file will /not/ compile unless you have defined
> FOUR somewhere else before calling COMPILE-FILE...
>
> Regards,
> --
> Nils Goesche
> "Don't ask for whom the <CTRL-G> tolls."
>
> PGP key ID 0x42B32FC9

Stupid newbie should listen to his elders.  five minutes after replying to
Barry, I realized that I don't really need that behavior after all.  It took
Nils pointing out that strangeness of my solution to make me think about it
and realize that, in fact, I was trying to solve a case that wouldn't be
happening anyway.  On a side topic, Nils, can you elaborate for me why the
above would not compile?

Thank you for tolerating my goofie questions and responses.

Glenn Burnside
From: Nils Goesche
Subject: Re: Newbie macro question
Date: 
Message-ID: <lky9d4h2oa.fsf@pc022.bln.elmeg.de>
"Glenn Burnside" <··············@ni.com> writes:

> "Nils Goesche" <······@cartan.de> wrote in message
> ···················@pc022.bln.elmeg.de...
> > "Glenn Burnside" <··············@ni.com> writes:
> >
> > > "Barry Margolin" <······@genuity.net> wrote in message
> > > ······················@paloalto-snr1.gtei.net...
> > > > In article <··············@corp.supernews.com>,
> > > > Glenn Burnside <··············@ni.com> wrote:

> > > > >(defmacro build-string (control &rest args) (eval `(format nil
> ,control
> > > > >,@args)))
> > > > >

> > > > Just call FORMAT and return the string:
> > > >
> > > > (defmacro build-string (control &rest args)
> > > >   (apply #'format nil control args))
> > > >
> > > > In either implementation, be aware that you can't reference any local
> > > > variables, since they don't exist until run-time.

> > (defvar four 4)
> > (build-string "~A" four)
> >
> > in the same source file will /not/ compile unless you have defined
> > FOUR somewhere else before calling COMPILE-FILE...

> On a side topic, Nils, can you elaborate for me why the above would
> not compile?

When you compile a file with COMPILE-FILE, the compiler processes the
top-level forms in the file one by one, but usually does not evaluate
them, unless absolutely necessary for processing the rest of the file.
It will remember macro definitions, for instance, so they can be used
in the rest of the source file.  But if you put

(defvar four 4)

into the file, the compiler will probably remember that FOUR will be a
special variable, but it will /not/ bind FOUR to 4 at compile time.
For that to happen, you'd have to write something like

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar four 4))

as Barry Margolin mentioned.  If you leave out the EVAL-WHEN, FOUR
won't be bound to 4 until you actually load the file.  However, if the
file contains a line

(build-string "~A" four)

later on, and BUILD-STRING is your macro, the compiler will lookup its
definition and try to evaluate, at compile time, the list

(FORMAT NIL "~A" FOUR).  FOUR, however, is not bound to anything, as
the file is still being compiled, and not loaded, so this will fail
with an UNBOUND-VARIABLE error (at compile time).

All this is fully explained in the third chapter of the HyperSpec.

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9
From: Barry Margolin
Subject: Re: Newbie macro question
Date: 
Message-ID: <89KR8.18$317.2377@paloalto-snr1.gtei.net>
In article <··············@pc022.bln.elmeg.de>,
Nils Goesche  <······@cartan.de> wrote:
>"Glenn Burnside" <··············@ni.com> writes:
>> You know, I tried exactly that, but I found there's a difference in behavior
>> between your solution and mine:
>> In your solution, the macro arguments are not evaluated before they are
>> passed to format.  In mine, they are.  So, for below,
>> 
>> (defvar four 4)
>> (build-string "~A" four)
>> 
>> your solution creates the string "FOUR" and mine creates "4".
>> 
>> For my purposes, I'm looking for the behavior of my solution.

I said you shouldn't access local variables, but what I really should have
said was that you shouldn't access *any* variables.  Variables shouldn't be
considered available until run-time.

>Well, if your macro definition does exactly what you're looking for,
>good for you :-)  However, I think it is an extremely weird macro, and
>it would never occur to me to write such a thing.  For instance,
>
>(defvar four 4)
>(build-string "~A" four)
>
>in the same source file will /not/ compile unless you have defined
>FOUR somewhere else before calling COMPILE-FILE...

Or put the variable definition in an eval-when:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar four 4))

(build-string "~A" four)

I also think that what you're doing is very poor style, because it will
have surprising results.  Consider:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar four 4))

(defun my-function ()
  (princ (build-string "~A" four)))

(setq four 4.0)

(my-function)

This looks like it should print "4.0", but it will print "4" because
build-string snapshotted the old value of FOUR.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, 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.
From: Gabe Garza
Subject: Re: Newbie macro question
Date: 
Message-ID: <d6ugmbut.fsf@anubis.kynopolis.org>
"Glenn Burnside" <··············@ni.com> writes:

> I've gotten stumped on a macro I'm trying to write.  I'm open to any
> suggestions, as I could be entirely off base with my approach.  I'm trying
> to write a macro that acts like format, but generates a string when it is
> evaluated, rather than at run-time.  The best I've come up with is:
> 
> (defmacro build-string (control &rest args) (eval `(format nil ,control
> ,@args)))
> 
> But everything I've read says - don't use eval, you don't need it, that's
> what macros are for, etc.  Is there a better way to do this?

Here's how I'd do it (this doesn't involve writing a macro):

Common Lisp has a standard reader macro `#.' that can be used to
evaluate a form at read time.  So you could write

#.(format nil "~4,'0D" 2) 

And it would be read as "0002"--FORMAT wouldn't be called at run-time.  It's
even less typing then using a BUILD-STRING macro. ;)  

If this doesn't make much sense, play around with it a little in the REPL:

[1]> (defun foo () #.(progn (print "The form was evaluated!") 
                            (format nil "~A-~D" "foo" 3)))

"The form was evaluated!" 
FOO
[2]> (foo)
"foo-3"


Gabe Garza
From: Kaz Kylheku
Subject: Re: Newbie macro question
Date: 
Message-ID: <afb316$k1u$2@luna.vcn.bc.ca>
In article <··············@corp.supernews.com>, Glenn Burnside wrote:
> I've gotten stumped on a macro I'm trying to write.  I'm open to any
> suggestions, as I could be entirely off base with my approach.  I'm trying
> to write a macro that acts like format, but generates a string when it is
> evaluated, rather than at run-time.  The best I've come up with is:
> 
> (defmacro build-string (control &rest args) (eval `(format nil ,control
> ,@args)))
> 
> But everything I've read says - don't use eval, you don't need it, that's
> what macros are for, etc.  Is there a better way to do this?

One tool you should know about is read-time evaluation via the #. reader 
macro:

  #.(format nil ... )

This will evaluate the form, and return the resulting object
as though that object were read from the program stream.