From: Jim Menard
Subject: Macros that build function names
Date: 
Message-ID: <wsqoez9xpg1.fsf@io.com>
I would appreciate help writing a macro. Originally, I wrote two pairs of
similar methods. In each pair, one function XXX-as-string is implemented in
terms of XXX-to-stream. Here is one pair as an example, where XXX is "tag".

    ;; Output the tag to a stream
    (defun tag-to-stream (tag stream)
      ( ... )) ; interesting code goes here

    ;; Return the tag as a string.
    (defun tag-as-string (tag)
      (with-output-to-string (stream) (tag-to-stream tag stream)))

I started to write a macro like this

    ;; Creates a <type>-as-string method that calls <type>-to-stream.
    (defmacro as-string (type-name)
      `(with-output-to-string (stream) (,type-name

and I got stuck. How do I concatenate the macro argument with type-name
"-to-stream" to form the function name <type-name>-to-stream that I am
trying to generate? In other words, I want the macro call

    (as-string tag)

to generate

    (with-output-to-string (stream) (tag-to-stream tag stream))

Thank you for any pointers and help.

Jim
-- 
Jim Menard, ····@io.com, http://www.io.com/~jimm/
"I want to be remembered as someone who's not dead." -- Christine Peterson

From: Erann Gat
Subject: Re: Macros that build function names
Date: 
Message-ID: <gat-0108031037460001@k-137-79-50-101.jpl.nasa.gov>
In article <···············@io.com>, Jim Menard <····@io.com> wrote:

> I would appreciate help writing a macro. Originally, I wrote two pairs of
> similar methods. In each pair, one function XXX-as-string is implemented in
> terms of XXX-to-stream. Here is one pair as an example, where XXX is "tag".
> 
>     ;; Output the tag to a stream
>     (defun tag-to-stream (tag stream)
>       ( ... )) ; interesting code goes here
> 
>     ;; Return the tag as a string.
>     (defun tag-as-string (tag)
>       (with-output-to-string (stream) (tag-to-stream tag stream)))
> 
> I started to write a macro like this
> 
>     ;; Creates a <type>-as-string method that calls <type>-to-stream.
>     (defmacro as-string (type-name)
>       `(with-output-to-string (stream) (,type-name
> 
> and I got stuck. How do I concatenate the macro argument with type-name
> "-to-stream" to form the function name <type-name>-to-stream that I am
> trying to generate? In other words, I want the macro call
> 
>     (as-string tag)
> 
> to generate
> 
>     (with-output-to-string (stream) (tag-to-stream tag stream))
> 
> Thank you for any pointers and help.
> 
> Jim

The easiest way to do this is:

(defun symcat (&rest things)
  "Create a symbol whose name is the concetenation of the names of all the
THINGs"
  (intern (concatenate 'string (format nil "~{~A~}" things))))

(defmacro as-string (type-name)
  `(with-output-to-string (stream) (,(symcat type-name '-to-stream) ...

IMHO this is a Really Bad Design (tm).

A better way is this:

(defmacro as-string (type-name)
  `(with-output-to-string (stream) (,(translate-type-for-as-string-macro
type-name) ...

(defun translate-type-for-as-string-macro (type-name)
  (ecase type-name
    (tag 'tag-to-string)
    ...)))

or

(defun translate-type-for-as-string-macro (type-name)
  (or (getf '(tag tag-to-string ...) type-name))
      (error "~A is not a valid type name for this macro" type-name)))

E.
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m3brv9xovw.fsf@javamonkey.com>
Jim Menard <····@io.com> writes:

> How do I concatenate the macro argument with type-name "-to-stream"
> to form the function name <type-name>-to-stream that I am trying to
> generate? In other words, I want the macro call
> 
>     (as-string tag)
> 
> to generate
> 
>     (with-output-to-string (stream) (tag-to-stream tag stream))
> 
> Thank you for any pointers and help.

   (intern (format nil "~a~a" 'tag '-to-stream))

Or, in the context of your macro where tag is a macro argument:

  (defmacro as-string (type-name)
    `(with-output-to-string (stream)
       (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Paul F. Dietz
Subject: Re: Macros that build function names
Date: 
Message-ID: <BcSdnXB3KdskiLaiU-KYgg@dls.net>
Peter Seibel wrote:

>    (intern (format nil "~a~a" 'tag '-to-stream))
> 
> Or, in the context of your macro where tag is a macro argument:
> 
>   (defmacro as-string (type-name)
>     `(with-output-to-string (stream)
>        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))

It's usually a mistake to call INTERN without specifying the package
argument.

	Paul
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m3wudwx0mj.fsf@javamonkey.com>
"Paul F. Dietz" <·····@dls.net> writes:

> Peter Seibel wrote:
> 
> >    (intern (format nil "~a~a" 'tag '-to-stream))
> > Or, in the context of your macro where tag is a macro argument:
> >   (defmacro as-string (type-name)
> >     `(with-output-to-string (stream)
> >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))
> 
> It's usually a mistake to call INTERN without specifying the package
> argument.

Good point. I suppose in this case we can assume foo-to-stream is
going to be from the same package as foo and thus write:

  (intern (format nil "~a~a" type-name 'to-stream) (symbol-package type-name))

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Paul F. Dietz
Subject: Re: Macros that build function names
Date: 
Message-ID: <SgKdnVMUNdP_vraiXTWJjQ@dls.net>
Peter Seibel wrote:

> Good point. I suppose in this case we can assume foo-to-stream is
> going to be from the same package as foo and thus write:
> 
>   (intern (format nil "~a~a" type-name 'to-stream) (symbol-package type-name))

But what happens if type-name is not interned?

This bug has caused all sorts of internal problems in some lisp implementations.

	Paul
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m3smokwnrk.fsf@javamonkey.com>
"Paul F. Dietz" <·····@dls.net> writes:

> Peter Seibel wrote:
> 
> > Good point. I suppose in this case we can assume foo-to-stream is
> > going to be from the same package as foo and thus write:
> >   (intern (format nil "~a~a" type-name 'to-stream) (symbol-package
> > type-name))
> 
> But what happens if type-name is not interned?

Well, we're talking about a macro where type-name is a macro variable
whose value is a symbol (notice no quote before type-name). The macro
can't be invoked without reading the symbol so it's going to be
interned unless someone invokes it with an #: name. Which would fall,
I think, in the category of they get what they deserve. Or maybe I'm
missing some subtlety--in which case I'd love to hear more.

Assuming I'm not missing anything in this case, I get what you're
saying--in general one needs to be careful about these kinds of games.

> This bug has caused all sorts of internal problems in some lisp
> implementations.

Which, not passing a pacakge to INTERN or using symbol-package to get
a package off a symbol that may not be interned?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Paul F. Dietz
Subject: Re: Macros that build function names
Date: 
Message-ID: <kiKdnVK4VeutMbaiXTWJiA@dls.net>
Peter Seibel wrote:

>>This bug has caused all sorts of internal problems in some lisp
>>implementations.
> 
> Which, not passing a pacakge to INTERN or using symbol-package to get
> a package off a symbol that may not be interned?

Both, I think.  The idea is you have some symbol FOO, and internal
functions needs to be generated from FOO.  So FOO-INTERNAL-BAR,
FOO-INTERNAL-BAZ, etc. get generated.  This screws up if
symbol-package of FOO is NIL, and would still screw up if you
didn't intern the generated symbol in that case, since you'd
generate different symbols each time.

One thing this led to is internal function names that are not
symbols:  (INTERNAL-BAR FOO), (INTERNAL-BAZ FOO), etc.

	Paul
From: David Golden
Subject: Re: Macros that build function names
Date: 
Message-ID: <235b265c.0308030443.9a61cc4@posting.google.com>
"Paul F. Dietz" <·····@dls.net> wrote in message 
> 
> One thing this led to is internal function names that are not
> symbols:  (INTERNAL-BAR FOO), (INTERNAL-BAZ FOO), etc.
> 

Wacky idea:
Why not allow lists as symbol-names? 
"composite symbols" or something?
Are symbol-names always strings? (in CL, I think yes) 
Could you have a lisp where you could use a non-string as a
symbol-name?

 (Note that it's the morning after the night before, I'm hung over and
therefore stupider than usual)

  Perhaps a language where any equal or equalp comparable lisp object
with structure can be a name, symbol-name->symbol resolution could be
akin equal-hashtables, and you could do reflective programming with
composite symbols made of lists as an alternative to OO or whatever???
 Here's a half-baked hypothetical, with, for the sake of argument,
maybe  (symnamed ...) is a form stating a symbol name #n(...)=>
(symnamed (backquote ...)) or something:


(setf people '(david daniel peter))

(setf pies `(
  ,(make-pie :filling :blueberry)
  ,(make-pie :filling :apple)
  ,(make-pie :filling :tomato)))

(setf #n(pie (of david)) (car pies))
(setf #n(pie (of daniel)) (cadr pies))
(setf #n(pie (of daniel)) (caddr pies))

(defun eat-pies-of-people (people-with-pies)
  (mapcar
    (lambda (person)
      (eat #n(pie (of ,person))))
   people-with-pies))

(eat-pies-of-people people)
From: Erann Gat
Subject: Re: Macros that build function names
Date: 
Message-ID: <gat-0208032125060001@dialin-077.jpl.nasa.gov>
In article <··············@javamonkey.com>, Peter Seibel
<·····@javamonkey.com> wrote:

> Well, we're talking about a macro where type-name is a macro variable
> whose value is a symbol (notice no quote before type-name). The macro
> can't be invoked without reading the symbol

Nope.

? (setf s (make-symbol "foo"))
#:|foo|
? (defmacro #.s () t)
#:|foo|
? (#.s)
T
? 

Things like this could actually arise in code-generating code.

E.
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m3k79uwnri.fsf@javamonkey.com>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <··············@javamonkey.com>, Peter Seibel
> <·····@javamonkey.com> wrote:
> 
> > Well, we're talking about a macro where type-name is a macro variable
> > whose value is a symbol (notice no quote before type-name). The macro
> > can't be invoked without reading the symbol
> 
> Nope.
> 
> ? (setf s (make-symbol "foo"))
> #:|foo|
> ? (defmacro #.s () t)
> #:|foo|
> ? (#.s)
> T
> ? 
> 
> Things like this could actually arise in code-generating code.

If you say so. (By which I mean--I'm having hard time imagining it but
also accept that there's lots of things I can't imagine that are
nonetheless the case.) But I was talking about rather simpler cases
like this:

  (defmacro foo (sym) 
    `(let ((new-symbol ',(intern (format nil "~a~a" sym '-related) (symbol-package sym))))
       (format t "Made related symbol ~s in package ~s~%" new-symbol (symbol-package new-symbol))))

Unless one writes code like this:

  (foo #:uninterned-symbol)

or, I suppose, following your example:

  (foo #.(make-symbol "foo"))

then there's no danger (unless I'm missing something) that the symbol
that FOO gets to munch on is not interned since it had to be read.

Also, there are lots of kinds of values that won't work well as
arguments to FOO. For instance:

  (foo "bar")
  (foo (list 'bar))
  (foo 10)

Given that Lisp isn't a bondage and discipline language, it seems that
we're supposed to be able to rely on users of functions and macros to
use them properly. If the point of a macro (as the macro the OP was
talking about) is to use an existing function name to generate a new
function with a related name, it doesn't seem crazy to assume that the
first function is named with an interned symbol. Especially if part of
the purpose of the macro is to create the name of new function in the
same package as the original.

Of course, if that's not what you want you could always use INTERN
with no package argument and get the new symbol interned in the
current package. (Of course my doing that is what started this
sub-thread, when Paul pointed out that that's a bad idea. Though now
that I think about it, I may have given in a bit too easily on that
point--DEFSTRUCT for example, interns the names it creates in the
current package.)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kent M Pitman
Subject: Re: Macros that build function names
Date: 
Message-ID: <sfwy8y9cjap.fsf@shell01.TheWorld.com>
Peter Seibel <·····@javamonkey.com> writes:

> "Paul F. Dietz" <·····@dls.net> writes:
> 
> > Peter Seibel wrote:
> > 
> > >    (intern (format nil "~a~a" 'tag '-to-stream))
> > > Or, in the context of your macro where tag is a macro argument:
> > >   (defmacro as-string (type-name)
> > >     `(with-output-to-string (stream)
> > >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))

Gack.

Don't procedurally embed a kludgey, arbitrary mechanism for name generation.
Use (get type-name 'as-string-function) if you must do it this way.

But why aren't you using generic functions?

But even WITH-OUTPUT-TO-STRING is expensive in some implementations.
I bet this is going to result in horrible performance in some
implementation.  Why not just use a function that knows whether going
to a stream or just doing direct output is better.  Consider that for
symbols, turning something into a string is just a matter of a
built-in coercion--going through streams is quite the long way around.

> > It's usually a mistake to call INTERN without specifying the package
> > argument.
> 
> Good point. I suppose in this case we can assume foo-to-stream is
> going to be from the same package as foo and thus write:
> 
>   (intern (format nil "~a~a" type-name 'to-stream) (symbol-package type-name))

Considerable community experience with the above technique showed it to
be bogus.  As a general rule: don't do it.

Use *package* for generated symbols.  It will usually be the same.

Even better: allow the user to also override the symbol chosen
 (which the implementation using GET I suggested above will do).
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m37k5tw5pw.fsf@javamonkey.com>
Kent M Pitman <······@world.std.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
> 
> > "Paul F. Dietz" <·····@dls.net> writes:
> > 
> > > Peter Seibel wrote:
> > > 
> > > >    (intern (format nil "~a~a" 'tag '-to-stream))
> > > > Or, in the context of your macro where tag is a macro argument:
> > > >   (defmacro as-string (type-name)
> > > >     `(with-output-to-string (stream)
> > > >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))
> 
> Gack.
> 
> Don't procedurally embed a kludgey, arbitrary mechanism for name
> generation. Use (get type-name 'as-string-function) if you must do
> it this way.

Are you saying it's never appropriate for macros to generate new names
based on other names. Isn't that what DEFSTRUCT does? (Note, I wasn't
the one who originally proposed this AS-STRING macro--I was just
trying to answer the question about creating new symbols in the
context of the original question.)

> But why aren't you using generic functions?

Dunno. Maybe the OP can comment.

> But even WITH-OUTPUT-TO-STRING is expensive in some implementations.
> I bet this is going to result in horrible performance in some
> implementation. Why not just use a function that knows whether going
> to a stream or just doing direct output is better. Consider that for
> symbols, turning something into a string is just a matter of a
> built-in coercion--going through streams is quite the long way
> around.

Fair enough. I hope the OP is still reading.

> > > It's usually a mistake to call INTERN without specifying the package
> > > argument.
> > 
> > Good point. I suppose in this case we can assume foo-to-stream is
> > going to be from the same package as foo and thus write:
> > 
> >   (intern (format nil "~a~a" type-name 'to-stream) (symbol-package type-name))
> 
> Considerable community experience with the above technique showed it to
> be bogus.  As a general rule: don't do it.
> 
> Use *package* for generated symbols.  It will usually be the same.

Yeah, I realized that later (c.f. my later reply to Erann Gat later in
this thread). So are you disagreing with Paul's statement that "it's
usually a mistake to call INTERN without specifying the package
argument"? If so, I think I agree with you.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kent M Pitman
Subject: Re: Macros that build function names
Date: 
Message-ID: <sfwn0epjc8s.fsf@shell01.TheWorld.com>
Peter Seibel <·····@javamonkey.com> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> > 
> > > "Paul F. Dietz" <·····@dls.net> writes:
> > > 
> > > > Peter Seibel wrote:
> > > > 
> > > > >    (intern (format nil "~a~a" 'tag '-to-stream))
> > > > > Or, in the context of your macro where tag is a macro argument:
> > > > >   (defmacro as-string (type-name)
> > > > >     `(with-output-to-string (stream)
> > > > >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))
> > 
> > Gack.
> > 
> > Don't procedurally embed a kludgey, arbitrary mechanism for name
> > generation. Use (get type-name 'as-string-function) if you must do
> > it this way.
> 
> Are you saying it's never appropriate for macros to generate new names
> based on other names.


As a point of style, I think it's never appropriate for other-than-definition
macros to do this, and moreover that it's probably not appropriate for anything
to do this that doesn't allow you to override the choice of symbol.

My style suggestion, not rule of law. 

> Isn't that what DEFSTRUCT does?

It's a definition macro.  Single point of control.  After that you just
use the name.  The problem with non-definition-macros is you use them 
multiple places and might use them incompabitibly if given the ability
to control it in the way I suggested.

> (Note, I wasn't
> the one who originally proposed this AS-STRING macro--I was just
> trying to answer the question about creating new symbols in the
> context of the original question.)

I wasn't scolding any particular person.  Just the coding style. ;)
 
> > But why aren't you using generic functions?
> 
> Dunno. Maybe the OP can comment.
> 
> > But even WITH-OUTPUT-TO-STRING is expensive in some implementations.
> > I bet this is going to result in horrible performance in some
> > implementation. Why not just use a function that knows whether going
> > to a stream or just doing direct output is better. Consider that for
> > symbols, turning something into a string is just a matter of a
> > built-in coercion--going through streams is quite the long way
> > around.
> 
> Fair enough. I hope the OP is still reading.
 
I guess I'll add that in various versions of LispWorks I've dealt with
(have not checked the latest version, the WITH-xxx stream operations all 
seem to cons huge blocks, which I think are probably buffer blocks of
some kind, that make me never want to use any over their WITH-xxx functions;
I've written my own suite of alternatives that are not stream-based to deal
with this big problem).  More generally, though, the spec doesn't say what
is or is not consed, so this isn't something implementations are bound to
do a certain way.

> > > > It's usually a mistake to call INTERN without specifying the package
> > > > argument.
> > > 
> > > Good point. I suppose in this case we can assume foo-to-stream is
> > > going to be from the same package as foo and thus write:
> > > 
> > >   (intern (format nil "~a~a" type-name 'to-stream) (symbol-package type-name))
> > 
> > Considerable community experience with the above technique showed it to
> > be bogus.  As a general rule: don't do it.
> > 
> > Use *package* for generated symbols.  It will usually be the same.
> 
> Yeah, I realized that later (c.f. my later reply to Erann Gat later in
> this thread). So are you disagreing with Paul's statement that "it's
> usually a mistake to call INTERN without specifying the package
> argument"? If so, I think I agree with you.

Yes, I guess I am, since in effect calling intern with no second argument is
calling it with *PACKAGE*, which I believe is the correct arg.  This implies
you should use a certain degree of care about when to call such operations,
but that's life.
From: Peter Seibel
Subject: Re: Macros that build function names
Date: 
Message-ID: <m3y8y8vps3.fsf@javamonkey.com>
Kent M Pitman <······@world.std.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
> 
> > Kent M Pitman <······@world.std.com> writes:
> > 
> > > Peter Seibel <·····@javamonkey.com> writes:
> > > 
> > > > "Paul F. Dietz" <·····@dls.net> writes:
> > > > 
> > > > > Peter Seibel wrote:
> > > > > 
> > > > > >    (intern (format nil "~a~a" 'tag '-to-stream))
> > > > > > Or, in the context of your macro where tag is a macro argument:
> > > > > >   (defmacro as-string (type-name)
> > > > > >     `(with-output-to-string (stream)
> > > > > >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))
> > > 
> > > Gack.
> > > 
> > > Don't procedurally embed a kludgey, arbitrary mechanism for name
> > > generation. Use (get type-name 'as-string-function) if you must do
> > > it this way.
> > 
> > Are you saying it's never appropriate for macros to generate new names
> > based on other names.
> 
> 
> As a point of style, I think it's never appropriate for
> other-than-definition macros to do this, and moreover that it's
> probably not appropriate for anything to do this that doesn't allow
> you to override the choice of symbol.
> 
> My style suggestion, not rule of law. 

I'm in total agreement. I didn't get into it with the OP since I
didn't want to muddy the waters, but since it seemed that what he
wanted was to define two functions foo-to-stream and foo-as-string
where foo-as-string was defined in terms of foo-to-stream (leaving
aside the question of whether that might not be better done with GF's)
that he should have some definitional macro that takes a single "type"
name 'foo' and creates both those functions, deriving both names from
it.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Jim Menard
Subject: Re: Macros that build function names
Date: 
Message-ID: <wsq1xvuh5lb.fsf@io.com>
Peter Seibel <·····@javamonkey.com> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> > 
> > > Kent M Pitman <······@world.std.com> writes:
> > > 
> > > > Peter Seibel <·····@javamonkey.com> writes:
> > > > 
> > > > > "Paul F. Dietz" <·····@dls.net> writes:
> > > > > 
> > > > > > Peter Seibel wrote:
> > > > > > 
> > > > > > >    (intern (format nil "~a~a" 'tag '-to-stream))
> > > > > > > Or, in the context of your macro where tag is a macro argument:
> > > > > > >   (defmacro as-string (type-name)
> > > > > > >     `(with-output-to-string (stream)
> > > > > > >        (,(intern (format nil "~a~a" type-name '-to-stream)) stream)))
> > > > 
> > > > Gack.
> > > > 
> > > > Don't procedurally embed a kludgey, arbitrary mechanism for name
> > > > generation. Use (get type-name 'as-string-function) if you must do
> > > > it this way.
> > > 
> > > Are you saying it's never appropriate for macros to generate new names
> > > based on other names.
> > 
> > 
> > As a point of style, I think it's never appropriate for
> > other-than-definition macros to do this, and moreover that it's
> > probably not appropriate for anything to do this that doesn't allow
> > you to override the choice of symbol.
> > 
> > My style suggestion, not rule of law. 
> 
> I'm in total agreement. I didn't get into it with the OP since I
> didn't want to muddy the waters, but since it seemed that what he
> wanted was to define two functions foo-to-stream and foo-as-string
> where foo-as-string was defined in terms of foo-to-stream (leaving
> aside the question of whether that might not be better done with GF's)
> that he should have some definitional macro that takes a single "type"
> name 'foo' and creates both those functions, deriving both names from
> it.

Original poster here. I have been away, and was unable to reply. Thank you
everyone for your comments.

My original train of thought went something like this: First, I was writing
a lot of pairs of functions named foo-to-stream and foo-to-string, where
foo-to-string called foo-to-stream in the same way no matter what type foo
is. Second, one of the ways I think of macros are as code generators. I
thought, why not write a macro that can write the function (or inline code)
foo-to-string that simply calls foo-to-stream.

Issue one: Implementing foo-to-string in terms of foo-to-stream may not be
good design. If not, please let me know what I should be doing instead.

Issue two: I couldn't figure out how to pass in "foo" (where foo is the
name of a struct type) and generate the function name "foo-to-string" or
call the function "foo-to-stream").

Issue three: I don't know if implementing foo-to-string in terms of
foo-to-stream is the LISP way of doing things.

I've actually rewritten the macro to take the function name, something
like this (this is from memory, so it may be horribly wrong):

    (defmacro as-string (arg-name type-to-stream)
	`(with-output-to-string (stream) (,type-to-stream arg-name stream)))

Again, thanks for all your comments.

Jim
-- 
Jim Menard, ····@io.com, http://www.io.com/~jimm/
"[H]ave these people *really* got so little to say, that they go around
quoting other people?"
    -- andyt
From: Coby Beck
Subject: Re: Macros that build function names
Date: 
Message-ID: <bh47dg$2t6e$1@otis.netspace.net.au>
"Jim Menard" <····@io.com> wrote in message ····················@io.com...
> Original poster here. I have been away, and was unable to reply. Thank you
> everyone for your comments.
>
> My original train of thought went something like this: First, I was
writing
> a lot of pairs of functions named foo-to-stream and foo-to-string, where
> foo-to-string called foo-to-stream in the same way no matter what type foo
> is. Second, one of the ways I think of macros are as code generators. I
> thought, why not write a macro that can write the function (or inline
code)
> foo-to-string that simply calls foo-to-stream.
>
> Issue one: Implementing foo-to-string in terms of foo-to-stream may not be
> good design. If not, please let me know what I should be doing instead.
>
> Issue two: I couldn't figure out how to pass in "foo" (where foo is the
> name of a struct type) and generate the function name "foo-to-string" or
> call the function "foo-to-stream").

You definately want generic functions.

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Jim Menard
Subject: Re: Macros that build function names
Date: 
Message-ID: <wsqr83tntn1.fsf@io.com>
"Coby Beck" <·····@mercury.bc.ca> writes:

> You definately want generic functions.

Thank you. Time for a Google search.

Jim
-- 
Jim Menard, ····@io.com, http://www.io.com/~jimm/
"Brought to you again by the Department of Redundancy Department."
    -- Firesign Theatre    
From: Rob Warnock
Subject: Re: Macros that build function names
Date: 
Message-ID: <jbidnf5KNtZr-qqiXTWc-g@speakeasy.net>
Jim Menard  <····@io.com> wrote:
+---------------
| "Coby Beck" <·····@mercury.bc.ca> writes:
| > You definately want generic functions.
| 
| Thank you. Time for a Google search.
+---------------

Don't forget to go straight to the source:

	<URL:http://www.lispworks.com/reference/HyperSpec/Body/07_f.htm>
	7.6 Generic Functions and Methods


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Paul F. Dietz
Subject: Re: Macros that build function names
Date: 
Message-ID: <B9-dnXZyGM-v4qqiU-KYgw@dls.net>
Jim Menard wrote:
> "Coby Beck" <·····@mercury.bc.ca> writes:
> 
> 
>>You definately want generic functions.
> 
> 
> Thank you. Time for a Google search.

In addition to the ANSI CL spec (which is somewhat dense), see Sonja Keene's
book "Object-Oriented Programming in Common Lisp".

	Paul
From: Rob Warnock
Subject: Re: Macros that build function names
Date: 
Message-ID: <NvednWDvaYM0GbKiXTWc-g@speakeasy.net>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| Peter Seibel <·····@javamonkey.com> writes:
| > Are you saying it's never appropriate for macros to generate new names
| > based on other names.
| 
| As a point of style, I think it's never appropriate for other-than-
| definition macros to do this, and moreover that it's probably not
| appropriate for anything to do this that doesn't allow you to override
| the choice of symbol.
| 
| My style suggestion, not rule of law. 
| 
| > Isn't that what DEFSTRUCT does?
| 
| It's a definition macro.  Single point of control.  After that you just
| use the name.
+---------------

So this use of it would be o.k., then?

    (defmacro deflex (var val &optional (doc nil docp))    
      "Defines a top level (global) lexical VAR with initial value VAL,
      which is assigned unconditionally as with DEFPARAMETER. If a DOC
      string is provided, it is attached to both the name |VAR| and the
      name *STORAGE-FOR-DEFLEX-VAR-|VAR|* as a documentation string of
      kind 'VARIABLE. The new VAR will have lexical scope and thus may
      be shadowed by LET bindings without affecting its global value."
      (let* ((s0 (load-time-value (symbol-name '#:*storage-for-deflex-var-)))
	     (s1 (symbol-name var))
	     (p1 (symbol-package var))
	     (s2 (load-time-value (symbol-name '#:*)))
	     (backing-var (intern (concatenate 'string s0 s1 s2) p1)))
       `(progn
	  (defparameter ,backing-var ,val ,@(when docp `(,doc)))
	  ,@(when docp
	      `((setf (documentation ',var 'variable) ,doc)))
	  (define-symbol-macro ,var ,backing-var))))

Notes:
1. It got called DEFLEX rather than DEFLEXICAL because almost all of
   my usage of it is typing directly into the REPL. (Fingers get tired...)
   It uses DEFPARAMETER semantics rather than DEFVAR for the same reason,
   that is, that's usually what you want when typing manually. [And it
   also matches the behavior of Scheme's top-level lexicals. (*ducks!*)]

2. I didn't parameterize the backing variable's name because I wanted
   the signature to match DEFVAR and DEFPARAMETER, specifically w.r.t.
   doc strings, and I didn't know how to do that without requiring a
   doc string if one wanted a non-default prefix (the &OPTIONAL versus
   &KEY issue). So I just picked a long prefix that seemed unlikely to
   ever conflict.

3. I specifically *did* intern the backing variable's symbol into the
   same package as the defined variable, so one could do the following
   without conflict:

	> (deflex foo 27)
	> (deflex bar::foo 13 "FOO in the BAR package")
	> (list foo bar::foo)
	(27 13)
	> (apropos 'foo)
	BAR::*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 13
	BAR::FOO [symbol macro] 
	*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 27
	FOO [symbol macro] 
	>

4. Thanks to the denizens comp.lang.lisp for many useful discussions
   (and flames!) on the topic of globals lexicals, and for the suggestion
   for the simple and efficient (albeit inelegant) "shadow" variable
   approach used above. [Note: Like several others, I had previously used
   a single global adjustable vector of shadow values, with complicated
   compile-time allocation of indices so that symbol-macro FOO expanded into
   something like (AREF *LEXICAL-STORE* (LOAD-TIME-VALUE {index-for-FOO})).
   But the above is much simpler.]


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kent M Pitman
Subject: Re: Macros that build function names
Date: 
Message-ID: <sfwd6fke5sv.fsf@shell01.TheWorld.com>
····@rpw3.org (Rob Warnock) writes:

> So this use of it would be o.k., then?
> 
>     (defmacro deflex (var val &optional (doc nil docp))    
>       "Defines a top level (global) lexical VAR with initial value VAL,
>       which is assigned unconditionally as with DEFPARAMETER. If a DOC
>       string is provided, it is attached to both the name |VAR| and the
>       name *STORAGE-FOR-DEFLEX-VAR-|VAR|* as a documentation string of
>       kind 'VARIABLE. The new VAR will have lexical scope and thus may
>       be shadowed by LET bindings without affecting its global value."
>       (let* ((s0 (load-time-value (symbol-name '#:*storage-for-deflex-var-)))

Sigh. What's the advantage of this over "STORAGE-FOR-DEFLEX-VAR-" ??

> 	     (s1 (symbol-name var))
> 	     (p1 (symbol-package var))
> 	     (s2 (load-time-value (symbol-name '#:*)))

And "*" ????

> 	     (backing-var (intern (concatenate 'string s0 s1 s2) p1)))
>        `(progn
> 	  (defparameter ,backing-var ,val ,@(when docp `(,doc)))
> 	  ,@(when docp
> 	      `((setf (documentation ',var 'variable) ,doc)))
> 	  (define-symbol-macro ,var ,backing-var))))

You don't have to use a symbol for this, btw.  A property or hash table
should suffice and is safer. 

> Notes:
> 1. It got called DEFLEX rather than DEFLEXICAL because almost all of
>    my usage of it is typing directly into the REPL. (Fingers get tired...)
>    It uses DEFPARAMETER semantics rather than DEFVAR for the same reason,
>    that is, that's usually what you want when typing manually. [And it
>    also matches the behavior of Scheme's top-level lexicals. (*ducks!*)]
> 
> 2. I didn't parameterize the backing variable's name because I wanted
>    the signature to match DEFVAR and DEFPARAMETER, specifically w.r.t.
>    doc strings, and I didn't know how to do that without requiring a
>    doc string if one wanted a non-default prefix (the &OPTIONAL versus
>    &KEY issue). So I just picked a long prefix that seemed unlikely to
>    ever conflict.

Yeah, I wouldn't either in this case.  Told you style rules were
not hard and fast.  But my reason for not using it is that it's not
intended for users to muck with.  (The usual reason for doing symbol
concatenation is to make nice names that people _do_ reference.)

I don't like the "unlikely" thing, though, since it's possible to turn
this heuristic into an algorithm by making better design choices.

> 3. I specifically *did* intern the backing variable's symbol into the
>    same package as the defined variable, so one could do the following
>    without conflict:
> 
> 	> (deflex foo 27)
> 	> (deflex bar::foo 13 "FOO in the BAR package")
> 	> (list foo bar::foo)
> 	(27 13)
> 	> (apropos 'foo)
> 	BAR::*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 13
> 	BAR::FOO [symbol macro] 
> 	*STORAGE-FOR-DEFLEX-VAR-FOO* [special variable] value: 27
> 	FOO [symbol macro] 
> 	>
>
> 4. Thanks to the denizens comp.lang.lisp for many useful discussions
>    (and flames!) on the topic of globals lexicals, and for the suggestion
>    for the simple and efficient (albeit inelegant) "shadow" variable
>    approach used above. [Note: Like several others, I had previously used
>    a single global adjustable vector of shadow values, with complicated
>    compile-time allocation of indices so that symbol-macro FOO expanded into
>    something like (AREF *LEXICAL-STORE* (LOAD-TIME-VALUE {index-for-FOO})).
>    But the above is much simpler.]

I usually just use a hash table or plist entry that contains a cons
cell to store into the cdr of.  (The car can usually be the symbol
name, just for self-doc of the cell.)
From: Rob Warnock
Subject: Re: Macros that build function names
Date: 
Message-ID: <D6ycncbcCIWTQKmiXTWc-g@speakeasy.net>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > (defmacro deflex (var val &optional (doc nil docp))    
...
| >   (let* ((s0 (load-time-value (symbol-name '#:*storage-for-deflex-var-)))
| 
| Sigh. What's the advantage of this over "STORAGE-FOR-DEFLEX-VAR-" ??
|
| > 	     (s2 (load-time-value (symbol-name '#:*)))
| And "*" ????
+---------------

It's only a visual reminder that there really *is* a normal special
variable out there that you'd better not try to bind. That is, when
someone does a DESCRIBE [at least in CMUCL] on the resulting lexical var,
they see both the documentation string and the backing variable name:

    > (deflex foo 42 "The answer to Life, The Universe, and Everything")

    FOO
    > (describe 'foo)

    FOO is an internal symbol in the COMMON-LISP-USER package.
    It is a symbol macro with expansion: *STORAGE-FOR-DEFLEX-VAR-FOO*.
    Macro documentation:
      The answer to Life, The Universe, and Everything
    > 

The "*...*" in the expansion is a reminder (to me, at least) that FOO
is really still only a special under the hood. That's all.

+---------------
| You don't have to use a symbol for this, btw.  A property or hash table
| should suffice and is safer. 
+---------------

Yes, well, I suspect those other implementations also have the following
problem, too, that no matter how useful the illusion of "globals lexicals"
is for interactive work, they're still *not* really first-class variables.
For example, given the above, this works fine:

    > (setf foo 26) 

    26
    > foo

    26
    >

but not this:

    > (setf (symbol-value 'foo) 53)

    53
    > foo

    26
    >

Oops!

+---------------
| I usually just use a hash table or plist entry that contains a cons
| cell to store into the cdr of.  (The car can usually be the symbol
| name, just for self-doc of the cell.)
+---------------

But then the run-time access of the "lexical" involves a hash table
lookup or GET overhead -- neither one negligible. Whereas the "backing
variable" approach really *is* just a variable access [after macroexpansion].

Anyway, it's not a biggy. The reason I use them at all is just so I
can type short, non-*...*'d names [e.g., "x" and "i"] at the listener
and not worry about some function's internal LET bindings accidentally
getting converted from lexical to special! That is, this:

	> (deflex x 27)
	> (load "foo.lisp")

is a *lot* safer than this:

	> (defvar x 27)
	> (load "foo.lisp")

And it works well enough for that.


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Joe Marshall
Subject: Re: Macros that build function names
Date: 
Message-ID: <4r0wdz5m.fsf@ccs.neu.edu>
Kent M Pitman <······@world.std.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>> 
>> Yeah, I realized that later (c.f. my later reply to Erann Gat later in
>> this thread). So are you disagreing with Paul's statement that "it's
>> usually a mistake to call INTERN without specifying the package
>> argument"? If so, I think I agree with you.
>
> Yes, I guess I am, since in effect calling intern with no second argument is
> calling it with *PACKAGE*, which I believe is the correct arg.  This implies
> you should use a certain degree of care about when to call such operations,
> but that's life.

I agree with Paul, but for the same reason you disagree.

I always explicitly supply the package argument when I call intern,
even if it is to pass the value of *package*.  I've gone so far as to
shadow the regular INTERN and substitute one that requires both
arguments.  The point being that one should think about what package
this operation will take place in, and by requiring the argument, you
are forced to think about it.

I always supply the second argument to merge-pathnames for the same
reason. 
From: Pekka P. Pirinen
Subject: Re: Macros that build function names
Date: 
Message-ID: <ixllu83tq0.fsf@ocoee.cam.harlequin.co.uk>
Kent M Pitman <······@world.std.com> writes:
> in various versions of LispWorks I've dealt with (have not checked
> the latest version, the WITH-xxx stream operations all seem to cons
> huge blocks, which I think are probably buffer blocks of some kind,

That was one of the reasons we implemented resources (not documented,
but the interface in Genera-compatible), reusing string streams and
stream buffers.  Should be in LW 4; at least LWW 4.2 has it.
-- 
Pekka P. Pirinen, Global Graphics Software
If it's spam, it's a scam.  Don't do business with net abusers.
From: Kent M Pitman
Subject: Re: Macros that build function names
Date: 
Message-ID: <sfw65lbeq02.fsf@shell01.TheWorld.com>
···············@globalgraphics.com (Pekka P. Pirinen) writes:

> Kent M Pitman <······@world.std.com> writes:
> > in various versions of LispWorks I've dealt with (have not checked
> > the latest version, the WITH-xxx stream operations all seem to cons
> > huge blocks, which I think are probably buffer blocks of some kind,
> 
> That was one of the reasons we implemented resources (not documented,
> but the interface in Genera-compatible), reusing string streams and
> stream buffers.  Should be in LW 4; at least LWW 4.2 has it.

Yes, you're right.  LW 4.2.7 seems to be pretty conservative these days.
(Too late, since all my code now does its own buffer abstractions that
I've come to like for expressional reasons.  I suppose I should consider
changing over and see if any remaining efficiency problems remain.)

Anyway, sorry for slighting LW without checking... 

(In my own defense, LW's WITH-OPEN-FILE still conses more than I
expect it to [9000+ bytes on every open of a text file], which is
something I have bug reported just now so don't really need to whine
about here; but it helps explain why my memory was confused, since I'd
filed these in the same place in my brain...)
From: Kenny Tilton
Subject: Re: Macros that build function names
Date: 
Message-ID: <3F2AA6D3.6070202@nyc.rr.com>
Jim Menard wrote:
> and I got stuck. How do I concatenate the macro argument with type-name
> "-to-stream" to form the function name <type-name>-to-stream that I am
> trying to generate? In other words, I want the macro call

   `(with-output-to-string (stream)
       (,(intern (concatenate 'string
          (string-upcase (symbol-name type-name) "-TO-STREAM")))...

Debuuging left as an exercise. :)

But can't you use GFs here?

(defmethod whatever-to-stream ((tag tag) stream)
    ....)



-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Everything is a cell." -- Alan Kay