From: Rainer Joswig
Subject: Macros and local functions
Date: 
Message-ID: <ium23enz.fsf@lise.lavielle.com>
Imagine having a lisp file with the following three lines:

(defmacro foo ()
   (flet ((bar98 () t))
      `(list ,#'bar98)))



Just to make sure I'll write a proper bug report,
compiling this file shouldn't necessarily
be successful (Genera & LWW), since it will try to dump
the function #'bar98 into the compiled file, right?

Would it be desireable that it would work (MCL & ACL)?
Should there be a warning?

Greetings,

Rainer Joswig

From: Kent M Pitman
Subject: Re: Macros and local functions
Date: 
Message-ID: <sfwn2bevdep.fsf@world.std.com>
Rainer Joswig <······@lavielle.com> writes:

> Imagine having a lisp file with the following three lines:
> 
> (defmacro foo ()
>    (flet ((bar98 () t))
>       `(list ,#'bar98)))
> 
> Just to make sure I'll write a proper bug report,
> compiling this file shouldn't necessarily
> be successful (Genera & LWW), since it will try to dump
> the function #'bar98 into the compiled file, right?
> 
> Would it be desireable that it would work (MCL & ACL)?
> Should there be a warning?

Strictly, this is not a compilation issue.  See the section in
CLHS about externalizable objects.  The above macro makes complete
sense for in-core compilation.  The problem isn't compiling it but
dumping it.  There isn't an external reprsentation guaranteed for
functions.  Indeed some implementations (I guess including the two
I've been associated with) do this, but I personally have a LOT of
philosophical quibbles with whether it means anything or really does
the right thing, and I'm quite comfortable with telling MCL & ACL
that they're doing fine by NOT supporting this, since I don't think
users should depend on it.  Rather, they should arrange for any 
support functions to be defined in the normal way, and they should be
using things like load-time-value to do load-time lookup of named
functions if that kind of efficiency is needed.  but frankly, if bar98
were global instead of a local, i don't see why `(list #'bar98) 
wouldn't be just as good.

It's reasonable for the compiler to warn about this, but ONLY the
file compiler, COMPILE-FILE, not the in-core compiler, COMPILE.
COMPILE is often asked to do (and is capable of) much more
interesting and tricky things because it isn't caught up in the
externalization problem.
From: Rainer Joswig
Subject: Re: Macros and local functions
Date: 
Message-ID: <hg1m395p.fsf@lise.lavielle.com>
Kent M Pitman <······@world.std.com> writes:

> Rainer Joswig <······@lavielle.com> writes:
> 
> > Imagine having a lisp file with the following three lines:
> > 
> > (defmacro foo ()
> >    (flet ((bar98 () t))
> >       `(list ,#'bar98)))
> > 
> > Just to make sure I'll write a proper bug report,
> > compiling this file shouldn't necessarily
> > be successful (Genera & LWW), since it will try to dump
> > the function #'bar98 into the compiled file, right?
> > 
> > Would it be desireable that it would work (MCL & ACL)?
> > Should there be a warning?
> 
> the right thing, and I'm quite comfortable with telling MCL & ACL

Oops, I didn't state that clearly. MCL and ACL are
dumping those functions. Genera and LWW not.
I just ran over code where somebody was assuming
this would work in general.

Thanks,

Rainer Joswig
From: Kent M Pitman
Subject: Re: Macros and local functions
Date: 
Message-ID: <sfw67i21e87.fsf@world.std.com>
Rainer Joswig <······@lavielle.com> writes:

> Oops, I didn't state that clearly. MCL and ACL are
> dumping those functions. Genera and LWW not.
> I just ran over code where somebody was assuming
> this would work in general.

Ah, then it's convenient that I said I didn't think not dumping them
was right since it means my reply would be the same the other way
around.  The fact is that I think this is a bad idea.

In Scheme, the only property of a function is that it computes a
certain result, and in fact I think functions are not even permitted
to be compared.  But in CL, functions have identity and in fact are
sometimes passed as arguments for the sake of that identity
(viz. MAKE-HASH-TABLE's :test argument).  It is not adequate for all
purposes to simply construct a function that computes the same value;
sometimes you need to construct a function that will be recognized as
EQ to a function obtained from #'this or #'that elsewhere in the 
environment, so it is pointless to dump out an equivalent function.
And sometimes you just have #'foo as a data object in many different
places and don't want to dump out separate copies becuase re-loading
them will take more storage than the original.  And almost always,
code that caches functions in this way will lose the ability to receive
patches by having the source of the function be updated.  Also, if
the function contains calls to LOAD-TIME-VALUE, the right setup will
not be done on re-load.  This could affect methods, since CLOS 
implementations sometimes do somethin glike this.  Consider:

 (defvar *the-frobs* (make-hash-table))
 (defmacro frob (x) `(gethash ',x *the-frobs*))
 (defmacro def-frob (x)
   `(setf (frob ,x) (make-array 20 :adjustable t :fill-pointer 0)))
 (defun foo (x) (position x (load-time-value (frob foo))))
 
Here let's assume (gethash *the-frobs* 'foo) yields an array and
adjusts the code vector of FOO so that it's as if the user had written
 (defun foo (x) (position x '#<ARRAY...>))
The problem is that if the system just dumps out a "similar" array and
reads it back in later in another environment where *the-frobs* has a 
different value, the FOO function will mysteriously perform wrong.
So the implementation has not helped you by pretending to have 
dumped out FOO "correctly" since the identiy of the constants in the
definition matters and in many cases it's possible to make it so the
function doesn't know how the constants were computed.

IMO, describing to users where they're going to win and where they're
going to lose is obviously hard since so many well-educated people in
this conversation seem to think it's a total win. ;-)
From: Michael Greenwald
Subject: Genera readtables [Was: Macros and local functions]
Date: 
Message-ID: <michaelg.898119235@Xenon.Stanford.EDU>
Kent M Pitman <······@world.std.com> writes:

>Btw, a similar issue comes up on the Lisp Machine for setting syntax.
>When I was at Symbolics, customers were always complaining about the
>fact that there were functions that were supposed to return the 
>readmacro used by various characters, and Genera returned NIL for 
>some important things, like parens.  The issue was the same there.
>In fact, Genera doesn't USE functions to read--it uses a single finite 
>state machine and calls out to user code for user-defined macros.  But
>there is no object that represents the state of the machine which is
>"reading balanced parens" and so it can't return one.  Sure, it could
>have done what CL asked it to do and rewritten its implementation, but
>it likely would have been slower.  So it chose not to conform.  

(Way off-topic here, but on to history) I have no way of checking now,
but I thought I implemented a "fix" for this in 7.1 or so.  If I
recall, I had GET-MACRO-CHARACTER return a closure that was
identifiable in some way.  If SET-MACRO-CHARACTER was called with one
of these special closures as an arg, I dug inside to figure out the
builtin syntax and made the correct change to the readtable.  That is,
 (SET-MACRO-CHARACTER X (GET-MACRO-CHARACTER Y)) 
worked (mostly) as CLtL spec'd, even if Y were #\(.  It was a terrible
kludge, so I don't remember if it was put in the system, or passed as
a private patch to customers who complained.

There was a bunch of packaging and repackaging of closures I had to do
in any case, because the ZL entry-points weren't changed.  You could
define, for example, a dispatching macro and set it using
CL:SET-DISPATCH-MACRO-CHARACTER.  If you got the function out of the
readtable using a ZL entrypoint, it would be wrapped in a closure so
that it had appropriate ZL dispatching macro arguments.  I don't
remember if I made the internal representation conform to CL or left
it as ZL.

This is not to argue with Kent's point.  Just to wonder if his
recollection in this other matter was totally correct.  Out of
curiosity, anyone with access to a LispM (or lispm sources): Was it
patched in?
From: Kent M Pitman
Subject: Re: Genera readtables [Was: Macros and local functions]
Date: 
Message-ID: <sfwsol3hbvs.fsf@world.std.com>
········@Xenon.Stanford.EDU (Michael Greenwald) writes:

> [...] I thought I implemented a "fix" for this in 7.1 or so.  If I
> recall, I had GET-MACRO-CHARACTER return a closure [...]
> This is not to argue with Kent's point.  Just to wonder if his
> recollection in this other matter was totally correct.  Out of
> curiosity, anyone with access to a LispM (or lispm sources): Was it
> patched in?

Since you asked, I just tried (get-macro-character #\() in Genera 8.3
on my Macivory.  It returns NIL.  [I tried it in both Symbolics Common
Lisp (CL84) and Symbolics "Future Common Lisp" (ANSI CL).]
From: Michael Greenwald
Subject: Re: Genera readtables [Was: Macros and local functions]
Date: 
Message-ID: <michaelg.898148710@Xenon.Stanford.EDU>
Kent M Pitman <······@world.std.com> writes:

>Since you asked, I just tried (get-macro-character #\() in Genera 8.3
>on my Macivory.  It returns NIL.  [I tried it in both Symbolics Common
>Lisp (CL84) and Symbolics "Future Common Lisp" (ANSI CL).]

Then my memory was incorrect.  Thanks.  (Age?  Exhaustion?)
From: David D. Smith
Subject: Re: Macros and local functions
Date: 
Message-ID: <dds-1506981203300001@x051.bit-net.com>
In article <············@lise.lavielle.com>, Rainer Joswig
<······@lavielle.com> wrote:

> Imagine having a lisp file with the following three lines:
> 
> (defmacro foo ()
>    (flet ((bar98 () t))
>       `(list ,#'bar98)))

Don't you want: 

(defmacro foo ()
   (flet ((bar98 () t))
      `(list ',#'bar98)))

I see nothing wrong with this...

d