From: Peter Seibel
Subject: Separating evaluation and compilation environments.
Date: 
Message-ID: <m31xcujdoe.fsf@javamonkey.com>
A few months ago I started (and dragged out to great length) a thread
in which I demonstrated my confusion about what the spec says about
evaluation and compilation environments vis a vis what happens when
they are separate. Eventually Duane Rettig got me straightened out.

Now I'm thinking about EVAL-WHEN and am curious to hear more about the
*advantages* of separating the evaluation and compilation
environments. Duane mentioned something about "late binding" in that
thread but it was a bit to compressed for me to grok. Having thought
about it a bit it seems to me that one definitely wants the startup
environment and evaluation environment to be different (lest
COMPILE-FILE "contaminate" the startup environment). But, I don't see
any advantage to keeping the evaluation and compilation environments
separate. But there must be some. Duane? Anyone?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4k6qlch4i.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> A few months ago I started (and dragged out to great length) a thread
> in which I demonstrated my confusion about what the spec says about
> evaluation and compilation environments vis a vis what happens when
> they are separate. Eventually Duane Rettig got me straightened out.
> 
> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
> *advantages* of separating the evaluation and compilation
> environments. Duane mentioned something about "late binding" in that
> thread but it was a bit to compressed for me to grok. Having thought
> about it a bit it seems to me that one definitely wants the startup
> environment and evaluation environment to be different (lest
> COMPILE-FILE "contaminate" the startup environment). But, I don't see
> any advantage to keeping the evaluation and compilation environments
> separate. But there must be some. Duane? Anyone?

Try this one:

(defvar *spy*)

(compile
 (defun foo (x)
   (macrolet ((bar ()
		(setq *spy* x)))
     (bar))))

(describe '*spy*)

In many lisps, you'll get an error, and *spy* will never get assigned.
However, in at least one lisp, you get some bleeding of compiler
internals from the lexical value of x, which is in the compilation
environment and was transferred to the evaluation environment.

All of the lisps are conforming; the problem is that the code above
is noncompliant.  (see the decription for macrolet, third paragraph
in the macrolet bullet).  But the behavior of bleeding compiler
internals is rather unfriendly.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m3pt0dgj8o.fsf@javamonkey.com>
Duane Rettig <·····@franz.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> A few months ago I started (and dragged out to great length) a thread
>> in which I demonstrated my confusion about what the spec says about
>> evaluation and compilation environments vis a vis what happens when
>> they are separate. Eventually Duane Rettig got me straightened out.
>> 
>> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
>> *advantages* of separating the evaluation and compilation
>> environments. Duane mentioned something about "late binding" in that
>> thread but it was a bit to compressed for me to grok. Having thought
>> about it a bit it seems to me that one definitely wants the startup
>> environment and evaluation environment to be different (lest
>> COMPILE-FILE "contaminate" the startup environment). But, I don't see
>> any advantage to keeping the evaluation and compilation environments
>> separate. But there must be some. Duane? Anyone?
>
> Try this one:
>
> (defvar *spy*)
>
> (compile
>  (defun foo (x)
>    (macrolet ((bar ()
> 		(setq *spy* x)))
>      (bar))))
>
> (describe '*spy*)
>
> In many lisps, you'll get an error, and *spy* will never get assigned.
> However, in at least one lisp, you get some bleeding of compiler
> internals from the lexical value of x, which is in the compilation
> environment and was transferred to the evaluation environment.
>
> All of the lisps are conforming; the problem is that the code above
> is noncompliant.  (see the decription for macrolet, third paragraph
> in the macrolet bullet).  But the behavior of bleeding compiler
> internals is rather unfriendly.

Uh, this is a bit cryptic. While I'm happy to believe that this code
behaves in any of number of weird ways in various compliant
implementations, I don't see how this demonstrates an advantage for
keeping the compilation and evaluation environments separate. Can you
dumb it down for me?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4ekgt3s39.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> A few months ago I started (and dragged out to great length) a thread
> >> in which I demonstrated my confusion about what the spec says about
> >> evaluation and compilation environments vis a vis what happens when
> >> they are separate. Eventually Duane Rettig got me straightened out.
> >> 
> >> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
> >> *advantages* of separating the evaluation and compilation
> >> environments. Duane mentioned something about "late binding" in that
> >> thread but it was a bit to compressed for me to grok. Having thought
> >> about it a bit it seems to me that one definitely wants the startup
> >> environment and evaluation environment to be different (lest
> >> COMPILE-FILE "contaminate" the startup environment). But, I don't see
> >> any advantage to keeping the evaluation and compilation environments
> >> separate. But there must be some. Duane? Anyone?
> >
> > Try this one:
> >
> > (defvar *spy*)
> >
> > (compile
> >  (defun foo (x)
> >    (macrolet ((bar ()
> > 		(setq *spy* x)))
> >      (bar))))
> >
> > (describe '*spy*)
> >
> > In many lisps, you'll get an error, and *spy* will never get assigned.
> > However, in at least one lisp, you get some bleeding of compiler
> > internals from the lexical value of x, which is in the compilation
> > environment and was transferred to the evaluation environment.
> >
> > All of the lisps are conforming; the problem is that the code above
> > is noncompliant.  (see the decription for macrolet, third paragraph
> > in the macrolet bullet).  But the behavior of bleeding compiler
> > internals is rather unfriendly.
> 
> Uh, this is a bit cryptic. While I'm happy to believe that this code
> behaves in any of number of weird ways in various compliant
> implementations, I don't see how this demonstrates an advantage for
> keeping the compilation and evaluation environments separate. Can you
> dumb it down for me?

It's a simple example; work it through.  What are the likely
"values" of x at the time of the macroexpansion?  (hint: read
http://www.franz.com/support/documentation/7.0/ansicl/dictentr/fletlabe.htm
concentrating on the third paragraph in the macrolet bullet,
and, knowing how environments must work, ask yourself what the
most likely bindings might be for x).  Note also that the compilation
is establishing a compilation environment, and the macroexpansion is
being done in an evaluation environment.  What if these are the
same environment?  How might they conflict?

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Christophe Rhodes
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <sq65256l57.fsf@cam.ac.uk>
Duane Rettig <·····@franz.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> Duane Rettig <·····@franz.com> writes:
>> 
>> > (defvar *spy*)
>> >
>> > (compile
>> >  (defun foo (x)
>> >    (macrolet ((bar ()
>> > 		(setq *spy* x)))
>> >      (bar))))
>> >
>> > (describe '*spy*)
>> >
>
>> Uh, this is a bit cryptic. While I'm happy to believe that this code
>> behaves in any of number of weird ways in various compliant
>> implementations, I don't see how this demonstrates an advantage for
>> keeping the compilation and evaluation environments separate. Can you
>> dumb it down for me?
>
> It's a simple example; work it through.

It's pretty cryptic to me too, I confess.  Why is "X has no binding at
any time during the compilation" the wrong answer?

Christophe
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4acrh3qta.fsf@franz.com>
Christophe Rhodes <·····@cam.ac.uk> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> Duane Rettig <·····@franz.com> writes:
> >> 
> >> > (defvar *spy*)
> >> >
> >> > (compile
> >> >  (defun foo (x)
> >> >    (macrolet ((bar ()
> >> > 		(setq *spy* x)))
> >> >      (bar))))
> >> >
> >> > (describe '*spy*)
> >> >
> >
> >> Uh, this is a bit cryptic. While I'm happy to believe that this code
> >> behaves in any of number of weird ways in various compliant
> >> implementations, I don't see how this demonstrates an advantage for
> >> keeping the compilation and evaluation environments separate. Can you
> >> dumb it down for me?
> >
> > It's a simple example; work it through.
> 
> It's pretty cryptic to me too, I confess.  Why is "X has no binding at
> any time during the compilation" the wrong answer?

Because it does in fact have a binding.

OK, let's go back a little, to see if we can pick up an "aha" 
moment or two.

What, precisely, is an environment?  It's a set of bindings,
right?  So what are the two bindings of X above?


-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Christophe Rhodes
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <sq1xct6j1j.fsf@cam.ac.uk>
Duane Rettig <·····@franz.com> writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
>
>> >> Duane Rettig <·····@franz.com> writes:
>> >> 
>> >> > (defvar *spy*)
>> >> >
>> >> > (compile
>> >> >  (defun foo (x)
>> >> >    (macrolet ((bar ()
>> >> > 		(setq *spy* x)))
>> >> >      (bar))))
>> >> >
>> >> > (describe '*spy*)
>> [...]
>> It's pretty cryptic to me too, I confess.  Why is "X has no binding at
>> any time during the compilation" the wrong answer?
>
> Because it does in fact have a binding.
>
> OK, let's go back a little, to see if we can pick up an "aha" 
> moment or two.

I'm game.

> What, precisely, is an environment?  It's a set of bindings,
> right?  So what are the two bindings of X above?

But I don't see that there are two bindings. :-)

There is a reference to a variable X in the body of the (MACROLET BAR)
macro-function; however, this variable is unbound in all environments
at compile-time, even if all the environments are the same.

If FOO is ever called, it will establish a lexical binding for a
variable (which happens to be named X at compile-time, but that's only
relevant for debug purposes); this variable is never referenced.

That's my view.  Working on the assumption that I'm missing
something...

Ah, wait a minute.  Are you referring to this paragraph?

  The macro-expansion functions defined by macrolet are defined in the
  lexical environment in which the macrolet form appears. Declarations
  and macrolet and symbol-macrolet definitions affect the local macro
  definitions in a macrolet, but the consequences are undefined if the
  local macro definitions reference any local variable or function
  bindings that are visible in that lexical environment.

If so, then I see.  (I'd also argue that there's a case for my
behaviour above to be considered strongly encouraged: see the comment
in MACROLET FUDGE in the first example; but I concede that it isn't
mandated).

Am I at least on the right track?  That formally the macrolet is
re-evaluated at each call to FOO, and the fact that the consequences
of accessing any run-time lexical state in the body of the local macro
function are undefined permits my interpretation (and indeed minimal
compilation) to happen for conforming code?

Christophe
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <41xcs53a2.fsf@franz.com>
Christophe Rhodes <·····@cam.ac.uk> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Christophe Rhodes <·····@cam.ac.uk> writes:
> >
> >> >> Duane Rettig <·····@franz.com> writes:
> >> >> 
> >> >> > (defvar *spy*)
> >> >> >
> >> >> > (compile
> >> >> >  (defun foo (x)
> >> >> >    (macrolet ((bar ()
> >> >> > 		(setq *spy* x)))
> >> >> >      (bar))))
> >> >> >
> >> >> > (describe '*spy*)
> >> [...]
> >> It's pretty cryptic to me too, I confess.  Why is "X has no binding at
> >> any time during the compilation" the wrong answer?
> >
> > Because it does in fact have a binding.
> >
> > OK, let's go back a little, to see if we can pick up an "aha" 
> > moment or two.
> 
> I'm game.

'Tis afoot...

> > What, precisely, is an environment?  It's a set of bindings,
> > right?  So what are the two bindings of X above?
> 
> But I don't see that there are two bindings. :-)
> 
> There is a reference to a variable X in the body of the (MACROLET BAR)
> macro-function; however, this variable is unbound in all environments
> at compile-time, even if all the environments are the same.

We are within a call to compile, are we not?  And there is a compilation
environment, is there not?  And there is a binding of X in that
compilation environment, is there not?  Where is that binding?
{remeber, there are two occurrences of the symbol "x" in the text.]

> If FOO is ever called, it will establish a lexical binding for a
> variable (which happens to be named X at compile-time, but that's only
> relevant for debug purposes); this variable is never referenced.

We never get as far as calling FOO in most CL implementations.  Let's
not get ahead of ourselves.  What binding is established _at_ _compile_
 _time_?

> That's my view.  Working on the assumption that I'm missing
> something...
> 
> Ah, wait a minute.  Are you referring to this paragraph?
> 
>   The macro-expansion functions defined by macrolet are defined in the
>   lexical environment in which the macrolet form appears. Declarations
>   and macrolet and symbol-macrolet definitions affect the local macro
>   definitions in a macrolet, but the consequences are undefined if the
>   local macro definitions reference any local variable or function
>   bindings that are visible in that lexical environment.

Well, yes, but what lexical environment are we talking about?
Earlier you said that X has no bindings in any of the environments!

> If so, then I see.  (I'd also argue that there's a case for my
> behaviour above to be considered strongly encouraged: see the comment
> in MACROLET FUDGE in the first example; but I concede that it isn't
> mandated).
> 
> Am I at least on the right track?  That formally the macrolet is
> re-evaluated at each call to FOO, and the fact that the consequences
> of accessing any run-time lexical state in the body of the local macro
> function are undefined permits my interpretation (and indeed minimal
> compilation) to happen for conforming code?

Not yet; I think you are considering the two occurrences of X to
be necessarily the same, and are trying to figure out a relationship
for them. If you an figure out what the bindings are, then I think
it will become completely clear what must happen.

FWIW, you're very close.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Marcus Breiing
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <iezeldmiq3op4@breiing.com>
* Duane Rettig
[To Christophe Rhodes]

> Earlier you said that X has no bindings in any of the environments!

There necessarily exists a binding in the compilation environment, but
does a compilation environment have to bind X to a _value_?  My guess
is that, given the halting problem, it probably doesn't:-)

Now, the language about the reference to X causing undefined behavior
means that a binding for X in the evaluation environment doesn't have
to bind X to a value either.

Thus, the Lisp may notice that, even though there may be a binding for
X (in any of our environments), it doesn't bind X to a _value_, and
emit an appropriate error.  Since to me that behavior seems both
possible and desirable no matter whether we have merged environments
or not, here's another one who can't see how your example argues
against merged environments.

Marcus


-- 
http://www.breiing.com/usenet/iezeldmiq3op4
(Use link after email address has expired)
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4hdln69qg.fsf@franz.com>
[ Looks like you're on to the answer, Marcus!
Just a few corrections ...]

Marcus Breiing <···············@breiing.com> writes:

> * Duane Rettig
> [To Christophe Rhodes]
> 
> > Earlier you said that X has no bindings in any of the environments!
> 
> There necessarily exists a binding in the compilation environment,

Yes, this is precisely the environment I was looking for.

> but
> does a compilation environment have to bind X to a _value_?

Yes.  By definition (look up the chain in the glossary) a compiler
environment is an environment, which has information about the form
being compiled.  An environment is defined simply to be a set of
bindings, and "binding" has a very interesting definition that says
"an assiciation between a name and that which the name denotes".
Note also that it goes further to say that a lexical binding
associates a name "and its value".

So what is the "value" of a variable in a compilation environment?
It is, as the compilation environment glossary term states:
compiler-specific information about the variable, within the form
being compiled.

>  My guess is that, given the halting problem, it probably doesn't:-)

No, there's no halting problem here.

> Now, the language about the reference to X causing undefined behavior
> means that a binding for X in the evaluation environment doesn't have
> to bind X to a value either.

It's interesting and appropriate that you stated this in this way:
"a binding ... does't have to bind ..." because that makes my job
easier of explaining this second environment.

Correct. X doesn't have a binding here, in this environment.  But what
precicely is _this_ environment?  It can possibly be the compilation
environment; but that one already has a binding for X, only if the
compilation and evaluaiton environments are merged.  It could be the
evaluation environment, if it is in fact disjoint from the compilation
environment.  Note, however, that in most CL implementaions (possibly
all?) every symbol has a value cell, and that value cell has _something_
in it, so we place a distignuished object there called the "unbound
value", where it thus represents the variable being in a state of
unbound-ness.  So implementationally, the variable is "bound to the
unbound value", but there is no support in the spec for this wording,
so the proper way to state this is that it is "unbound in the global
environment".  That is why accessing it will possibly result in an
unbound variable error.  Note from 3.2.1 that at compile-time, only
the evaluation and compilation environments are available, but since
the evaluation environment inherits from the global environment (i.e.
the startup environment) the same terminology could be used for the
evaluation environment as I have used here.

Now, what happens if the evaluation environment and the compilation
environment _are_ the same?  Well, let's try this out in at least one
version of Clisp:

[1]> (defvar *spy*)
*SPY*
[2]> (compile
 (defun foo (x)
   (macrolet ((bar ()
		(setq *spy* x)))
     (bar))))

Help (abbreviated :h) = this list
Use the usual editing capabilities.
(quit) or (exit) leaves CLISP.

Help (abbreviated :h) = this list
Use the usual editing capabilities.
(quit) or (exit) leaves CLISP.

WARNING in FOO :
variable X is not used.
Misspelled or missing IGNORE declaration?
FOO ;
1 ;
NIL
[3]> (describe '*spy*)

*SPY* is the symbol *SPY*, lies in #<PACKAGE COMMON-LISP-USER>, is accessible 
in 1 package COMMON-LISP-USER, a variable declared SPECIAL, value: 
#1=#<SYSTEM::VAR X NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL
     (1 .
      #2=#<SYSTEM::FNODE FOO #<COMPILED-CLOSURE FOO> NIL NIL NIL 0 NIL 0 NIL
           NIL 0 1 0 NIL NIL NIL NIL 0 (#1#) (NIL) NIL NIL NIL NIL NIL>)
     (NIL #2#) #2#>.
 
 #<PACKAGE COMMON-LISP-USER> is the package named COMMON-LISP-USER. It has 2 
 nicknames CL-USER, USER.
 It imports the external symbols of 2 packages COMMON-LISP, EXT and exports 
 no symbols, but no package uses these exports.
 
 #1=#<SYSTEM::VAR X NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL ...> is a 
 structure of type SYSTEM::VAR.
 No slots.

[4]> 


Now, what in the world is that value that *spy* now has?  I've never looked
at the Clisp compiler, but my informed guess is that it is a compiler
information structure that is marking the "value" of X in the _compiler_
environment (which in this case is also the evaluation environment).

Finally, an explanation of the other two lisps I tried is in order;
I _think_ that cmucl and sbcl both purport to have the same compilation
and evaluation environments (someone please correct me if I'm wrong; it
makes the explanation easier), and yet they each get the unbound-variable
error rather than compiler-environment bleed.  However, it may be that the
"value" slot of a lexical entry is in a different location in the two
environments, or else copies of the compiler-environment that are
relevant to the evaluation environment are made specially for the
macroexpansion of the macrolet.  In either case it would tend to
show the fuzziness of what it might mean to have merged compilation
and evaluation environmens...

> Thus, the Lisp may notice that, even though there may be a binding for
> X (in any of our environments), it doesn't bind X to a _value_, and
> emit an appropriate error.

Agreed, if the binding in the evaluation environment is indeed unbound.

>  Since to me that behavior seems both
> possible and desirable no matter whether we have merged environments
> or not, here's another one who can't see how your example argues
> against merged environments.

Hopefully after going through this you can now see the issue.

I also agree that an unbound-variable error is more desirable than
seeing compiler guts, but Clisp is entirely within its rights to
spill its guts when you perform such undefined behavior.  In fact,
I would argue that in a lisp which chooses to merge compilation and
evaluation environments, this behavior would be preferable, because
it indicates a more consisten internal representation of environments.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Marcus Breiing
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <q423wq67150pw@breiing.com>
* Duane Rettig

> So what is the "value" of a variable in a compilation environment?
> It is, as the compilation environment glossary term states:
> compiler-specific information about the variable, within the form
> being compiled.

I know we were looking at a lexical variable, but allow me to forget
that for a while.  Say we have a binding for a dynamic variable *foo*
in the startup environment, and say we have set its value to 20.

Because of what the spec says about inheritance, that binding should
be present in both the evaluation environment and the compilation
environment.  In the evaluation environment, *foo* evaluates to the
value 20, but that doesn't seem to be a very useful datum to be used
as compiler-specific information about the variable.

There is no problem as long as we look at a binding as "an assiciation
between a name and that which the name denotes", because denotation
can easily be context sensitive, which means there should be no
problem with having different denotations for compilation and
evaluation in the same environment.  I'm a bit puzzled as to why the
glossary entry for lexical environments (which I overlooked) is so
much more specific.

Additionally, in this reading, the lexical environments glossary entry
would seem to imply that the compiler must use function objects as its
compiler-specific information about the names of functions, while it
is free to use any kind of object for variable names.

Marcus

-- 
http://www.breiing.com/usenet/q423wq67150pw
(Use link after email address has expired)
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4pt0box97.fsf@franz.com>
Marcus Breiing <···············@breiing.com> writes:

> * Duane Rettig
> 
> > So what is the "value" of a variable in a compilation environment?
> > It is, as the compilation environment glossary term states:
> > compiler-specific information about the variable, within the form
> > being compiled.
> 
> I know we were looking at a lexical variable, but allow me to forget
> that for a while.  Say we have a binding for a dynamic variable *foo*
> in the startup environment, and say we have set its value to 20.

OK.

> Because of what the spec says about inheritance, that binding should
> be present in both the evaluation environment and the compilation
> environment.

Not necessarily.  It would have been a whole lot easier to picture all
of this if the Environments Access section (described in CLtL2) had
been adopted by the standard (though I believe that it was wise that
they removed it, since it had not been developed fully).  But perhaps
I can help enlighten somewhat, below, by showing you a mega-example.
But first, let's finish the corrections:

> In the evaluation environment, *foo* evaluates to the
> value 20, but that doesn't seem to be a very useful datum to be used
> as compiler-specific information about the variable.

It is true that 20 isn't a useful value for a compiler-environment
binding, unless it is a global binding (see the example below; hopefully
I'll remember to explain it - if not, remind me...)

> There is no problem as long as we look at a binding as "an assiciation
> between a name and that which the name denotes", because denotation
> can easily be context sensitive, which means there should be no
> problem with having different denotations for compilation and
> evaluation in the same environment.  I'm a bit puzzled as to why the
> glossary entry for lexical environments (which I overlooked) is so
> much more specific.

It basically lists the five namespaces, although it does so slightly
incorrectly.  The namespaces are in fact variable, function, tag, block,
and declare, (tag and block were left out even in the CLtL2 description),
and each of those namespaces have bindings of their own.  

> Additionally, in this reading, the lexical environments glossary entry
> would seem to imply that the compiler must use function objects as its
> compiler-specific information about the names of functions, while it
> is free to use any kind of object for variable names.

No, note that it says "among other things", so there is some wiggle
room.  I believe that the namespace issue is one of the ragged edges
of the spec, made so by the sudden withdrawal of the Environments
section of CLtL2 (starting on p 207).

=====

OK, now for my mega-example.  This is just toy code, and it
demonstrates some of Allegro CL's environments access interface.
You can see the documentation here:
http://www.franz.com/support/documentation/7.0/doc/environments.htm
and links to the individual pages for variable-information and
function-information are close to the top of that document.

I've modified the toy for this discussion, so it is fairly busy.
And since some of the values are compiler structs, which aren't
too friendly for printing, I load a file in that gives them much
more friendly print-object methods (so don't try this at home!).

Other than that intro, I'm sure there will be questions, so I
will just show the example without further explanation, for now.

Enjoy!


CL-USER(1): :ld debugstructs
; Loading /tmp_mnt/net/gemini/home/duane/debugstructs.cl
CL-USER(2): (shell "cat vifitest.cl")
(in-package :user)

(defmacro with-vi-test ((var &optional all) &body body &environment e)
  (format t "variable-information ~:[~;(all)~] of ~s is ~s~%"
	  all var (multiple-value-list (sys:variable-information var e all)))
  `(progn ,@body))

(defmacro with-fi-test ((var &optional all spec) &body body &environment e)
  (format t "function-information ~:[~;(all)~]~:[~; w/spec~] of ~s is ~s~%"
	  all spec var (multiple-value-list (sys:function-information var e all spec)))
  `(progn ,@body))

(defconstant seven 7)

(defvar *framis*)

(defmacro not-twelve (x)
  `(/= 12 ,x))

(define-symbol-macro not-eleven (1- seven))

(let ((x (multiple-value-list (get-universal-time))))
  (declare (special frob))
  (symbol-macrolet ((pie 22/7))
    (flet ((epi (x) (1+ x)))
      (macrolet ((poi (x)
		   `(sqrt ,x)))
	(defun load-time ()
	  (with-vi-test (x)
	    (with-vi-test (frob)
	      (with-vi-test (*print-base*)
		(with-vi-test (seven)
		  (with-vi-test (not-eleven)
		    (with-vi-test (pi)
		      (with-vi-test (pi t)
			(with-vi-test (*framis*)
			  (let ((*framis* 10.0))
			    (with-vi-test (*framis*)
			      (with-vi-test (unknown)
				(+ seven x)))))))))))))
	(defun apple-pie (apple)
	  (with-vi-test (apple)
	    (with-vi-test (pie)
	      (with-fi-test (or)
		(with-fi-test (or t)
		  (with-fi-test (or t t)
		    (with-fi-test (poi)
		      (with-fi-test (not-twelve)
			(with-fi-test (car)
			  (with-fi-test (car t)
			    (with-fi-test (epi)
			      (print
			       (values pi
				       (* apple pie))))))))))))))))))
0
CL-USER(3): :cf vifitest
;;; Compiling file vifitest.cl
variable-information  of X is (:LEXICAL
                               (#<COMPILER::VARREC X DynamicExtent: MAYBE
                                  Used: 0 Set: (#<MVC @ #x1066b672>)
                                  UNKNOWN-TYPE>)
                               NIL :OUTER)
variable-information  of FROB is (:SPECIAL
                                  (#<COMPILER::VARREC FROB Specialp: DECLARE
                                     DynamicExtent: MAYBE Used: 0
                                     UNKNOWN-TYPE>)
                                  NIL :OUTER)
variable-information  of *PRINT-BASE* is (:SPECIAL NIL NIL)
variable-information  of SEVEN is (:CONSTANT 7 NIL)
variable-information  of NOT-ELEVEN is (:SYMBOL-MACRO ((1- SEVEN)) NIL)
variable-information  of PI is (:CONSTANT 3.141592653589793d0 NIL)
variable-information (all) of PI is (:CONSTANT 3.141592653589793d0
                                     ((TYPE
                                       (DOUBLE-FLOAT
                                        3.141592653589793d0
                                        3.141592653589793d0))))
variable-information  of *FRAMIS* is (:SPECIAL NIL NIL)
variable-information  of *FRAMIS* is (:SPECIAL
                                      (#<COMPILER::VARREC
                                         *FRAMIS*
                                         Specialp: T
                                         DynamicExtent: MAYBE
                                         Used: 0
                                         Set: (#<CONSTANT 10.0 @ #x104cd622>)
                                         UNKNOWN-TYPE>)
                                      NIL :OUTER)
variable-information  of UNKNOWN is (NIL)
variable-information  of APPLE is (:LEXICAL
                                   (#<COMPILER::VARREC APPLE
                                      DynamicExtent: MAYBE Used: 0 Set: (T)
                                      UNKNOWN-TYPE>)
                                   NIL :OUTER)
variable-information  of PIE is (:SYMBOL-MACRO (22/7) NIL :OUTER)
function-information  of OR is (:MACRO NIL NIL)
function-information (all) of OR is (:MACRO
                                     (#<Function MACROEXPAND-1-TRANSFORM>) NIL)
function-information (all) w/spec of OR is (:SPECIAL-OPERATOR NIL NIL)
function-information  of POI is (:MACRO
                                 (#<Interpreted Function POI @ #x104cefaa>)
                                 NIL T)
function-information  of NOT-TWELVE is (:MACRO NIL NIL)
function-information  of CAR is (:FUNCTION NIL NIL)
function-information (all) of CAR is (:FUNCTION (#<Function CAR>) NIL)
function-information  of EPI is (:FUNCTION (#:G59) NIL T)
;;; Writing fasl file vifitest.fasl
;;; Fasl write complete
CL-USER(4): 

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Marcus Breiing
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <o66msi49s9pg8@breiing.com>
* Duane Rettig

> It would have been a whole lot easier to picture all of this if the
> Environments Access section (described in CLtL2) had been adopted by
> the standard

Maybe Environment Access is what this really hinges on.  As long as
you don't have an elaborate environment access system like the one
you're developing, it doesn't matter to a conforming program what a
name is bound to in the compilation environment.

> (though I believe that it was wise that they removed it, since it
> had not been developed fully).

I begin to suspect that, had it been developed more fully, something
like a way of distinguishing between bindings for the compiler and
bindings for evaluation /within the same environment/ would have
evolved, because, as it is now, environment access seems to have an
unintended consequence on whether you can have merged environments.

> It is true that 20 isn't a useful value for a compiler-environment
> binding, unless it is a global binding (see the example below;
> hopefully I'll remember to explain it - if not, remind me...)

If I see correctly, everything returned by envrionment access in your
example is an implementation specific information object - and I can
easily imagine that nothing else would be satisfying.

So, to sum up my understanding of your point, if environment access
returns "the" binding of a name (within one of the namespaces), we
don't want to merge envrironments and use environment access at the
same time.  To have our cake and eat it too, environment access maybe
could distinguish between a name's denotation for compilation and
evaluation within the same environment.

Marcus

-- 
Marcus Breiing

http://www.breiing.com/usenet/o66msi49s9pg8
(Use link after email address has expired)
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4r7kq8tbi.fsf@franz.com>
Marcus Breiing <···············@breiing.com> writes:

> * Duane Rettig
> 
> > It would have been a whole lot easier to picture all of this if the
> > Environments Access section (described in CLtL2) had been adopted by
> > the standard
> 
> Maybe Environment Access is what this really hinges on.  As long as
> you don't have an elaborate environment access system like the one
> you're developing, it doesn't matter to a conforming program what a
> name is bound to in the compilation environment.

This is not true; we had to deal with the macrolet bleed-through long
before we started the environments access project.  And at least one
other CL has it too.

> > (though I believe that it was wise that they removed it, since it
> > had not been developed fully).
> 
> I begin to suspect that, had it been developed more fully, something
> like a way of distinguishing between bindings for the compiler and
> bindings for evaluation /within the same environment/ would have
> evolved, because, as it is now, environment access seems to have an
> unintended consequence on whether you can have merged environments.

This (an unintended consequence) does not follow, because it is not
true; there _is_ a way to distinguish such bindings.  The CLtL2
version had specified it as the second value from variable-information
and function-information, but we moved it to be the fourth value
returned, because more often than not it doesn't make a difference;
analysis tools usually care most often what _kind_ of object the
name represents (this is the first value returned from each function),
and then in second place goes the binding, usually indirectly
referenced via a "locative" cons (but often one knows whether the
binding will be a traditional value or some other kind from the
context).  In third place is the declaration information - this info
is important to compilers, but mostly unimportant to interpreters
(note that a special declaration, which an interpreter can't ignore,
is handled differently, by making :special a first-value returned
from variable-information).  Lastly, there is what I call the "lex"
returned value; if this value is true, then the name has a binding
that shadows any global bindings, and this binding is the
implementation-dependent one (though note that for function-information,
the value we return for a macrolet is in fact a macro definition).
If the "lex" vaue returned is nil, then the binding is a global one,
and the second value likely represents the actual value (or if nil,
the actual value is to be accessed via a global accessor like
macro-function or symbol-value).

[Note that you might also see a value of :OUTER for the lex returned
value, instead of T; this indicates that the entry found is still
within the current contour - it is still possible to add declarations
to this binding using an augment-environment with :reuse t specified.
I don't really like this name; I may clean it up before I open-source
the module]

> > It is true that 20 isn't a useful value for a compiler-environment
> > binding, unless it is a global binding (see the example below;
> > hopefully I'll remember to explain it - if not, remind me...)
> 
> If I see correctly, everything returned by envrionment access in your
> example is an implementation specific information object - and I can
> easily imagine that nothing else would be satisfying.

You aren't seeing correctly; look at the examples more closely.
In fact _most_ of the bindings returned are completely traditional
return values.  I should have spent more time last night explaining
some of the values returned, but it was getting late, and I didn't
want to ramble...

If you look at the with-*-test macros, you'll see that each returns
the following: (multiple-value-list (sys:*-information var e ...))
This means that whatever values variable-information or
function-information are returning are consed up as a list and
printed.  This list is thus always of the form

 (kind [locative [declaration [lexical]]])

The kind return value might be nil, or, for variable-information,
it might be :special, :lexical, :symbol-macro, or :constant, and
for function-information it could be :function, :macro,
 :compiler-macro, or :special-operator.

The locative return value is sometimes nil (when the definition
is global) or it may be an actual value (in the case of a constant),
but it is usually a cons cell whose car is a context-sensitive
"value" (i.e. binding).

The declaration return value is self-explanatory, except that
the list of declarations never includes a SPECIAL declaration;
that is always transferred so as to return :special for the kind
value.


> So, to sum up my understanding of your point, if environment access
> returns "the" binding of a name (within one of the namespaces), we
> don't want to merge envrironments and use environment access at the
> same time.  To have our cake and eat it too, environment access maybe
> could distinguish between a name's denotation for compilation and
> evaluation within the same environment.

We have our cake and eat it, too - it is not compilation vs evaluation
that needs distinguishing, but lexical vs global, and this is being
done.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Rob Warnock
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <ysydnUyvHZz_KnncRVn-rQ@speakeasy.net>
Duane Rettig  <·····@franz.com> wrote:
+---------------
| Marcus Breiing <···············@breiing.com> writes:
| > Now, the language about the reference to X causing undefined behavior
| > means that a binding for X in the evaluation environment doesn't have
| > to bind X to a value either.
| 
| It's interesting and appropriate that you stated this in this way:
| "a binding ... does't have to bind ..." because that makes my job
| easier of explaining this second environment.
|  
| Correct. X doesn't have a binding here, in this environment.
| ...
| > Thus, the Lisp may notice that, even though there may be a binding for
| > X (in any of our environments), it doesn't bind X to a _value_, and
| > emit an appropriate error.
| 
| Agreed, if the binding in the evaluation environment is indeed unbound.
+---------------

This discussion reminds me of a very similar [or at least related] topic
that comes up from time to time, on whether DEFCONSTANT is required to
provide a value for the variable at compile time (it isn't, see [1]) as
opposed to merely noting that whenever the variable *does* eventually
have a value, it will be constant, so as to meet the contract between
DEFCONSTANT & CONSTANTP. As has been mentioned before, I bumped into
this with CMUCL while using macros originally written for LispWorks.[2]
Try compiling and loading the following small example and see what
*your* Lisp says:

    (defconstant +foo+ 37)

    (defmacro hack (x &environment e)
      (if (constantp x e)
	`(format t "~a"
	  ,(with-output-to-string (s)
	     (format s "C: +foo+ type = ~s, +foo+ = ~s~%" (type-of x) x)))
	`(format t "R: +foo+ type = ~s, +foo+ = ~s~%" (type-of ,x) ,x)))

    (hack +foo+)

CMUCL prints:           C: +foo+ type = SYMBOL, +foo+ = +FOO+
CLISP[3] prints:        R: +foo+ type = FIXNUM, +foo+ = 37
LispWorks[4] prints:    C: +foo+ type = FIXNUM, +foo+ = 37

Note that all three are technically legal[1,5], though only the last one
is useful for doing interesting partial evaluation at macroexpansion time.


-Rob

[1] CLHS "Macro DEFCONSTANT":

    If a defconstant form appears as a top level form, the compiler must
    recognize that name names a constant variable. An implementation may
    choose to evaluate the value-form at compile time, load time, or both.
    Therefore, users must ensure that the initial-value can be evaluated at
    compile time (regardless of whether or not references to name appear in
    the file) and that it always evaluates to the same value.

[2] <http://www.cliki.net/htout>

[3] On a fairly-old version. Recent ones may differ.

[4] If I remember/understand what Tim told me several years ago.

[5] CONSTANTP may return NIL if "it cannot be determined [presumably in
    that implementation --rpw3] whether or not form is a constant form".

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4llazouwu.fsf@franz.com>
····@rpw3.org (Rob Warnock) writes:

> Duane Rettig  <·····@franz.com> wrote:
> +---------------
> | Marcus Breiing <···············@breiing.com> writes:
> | > Now, the language about the reference to X causing undefined behavior
> | > means that a binding for X in the evaluation environment doesn't have
> | > to bind X to a value either.
> | 
> | It's interesting and appropriate that you stated this in this way:
> | "a binding ... does't have to bind ..." because that makes my job
> | easier of explaining this second environment.
> |  
> | Correct. X doesn't have a binding here, in this environment.
> | ...
> | > Thus, the Lisp may notice that, even though there may be a binding for
> | > X (in any of our environments), it doesn't bind X to a _value_, and
> | > emit an appropriate error.
> | 
> | Agreed, if the binding in the evaluation environment is indeed unbound.
> +---------------
> 
> This discussion reminds me of a very similar [or at least related] topic
> that comes up from time to time, on whether DEFCONSTANT is required to
> provide a value for the variable at compile time (it isn't, see [1]) as
> opposed to merely noting that whenever the variable *does* eventually
> have a value, it will be constant, so as to meet the contract between
> DEFCONSTANT & CONSTANTP. As has been mentioned before, I bumped into
> this with CMUCL while using macros originally written for LispWorks.[2]
> Try compiling and loading the following small example and see what
> *your* Lisp says:
> 
>     (defconstant +foo+ 37)
> 
>     (defmacro hack (x &environment e)
>       (if (constantp x e)
> 	`(format t "~a"
> 	  ,(with-output-to-string (s)
> 	     (format s "C: +foo+ type = ~s, +foo+ = ~s~%" (type-of x) x)))
> 	`(format t "R: +foo+ type = ~s, +foo+ = ~s~%" (type-of ,x) ,x)))
> 
>     (hack +foo+)
> 
> CMUCL prints:           C: +foo+ type = SYMBOL, +foo+ = +FOO+
> CLISP[3] prints:        R: +foo+ type = FIXNUM, +foo+ = 37
> LispWorks[4] prints:    C: +foo+ type = FIXNUM, +foo+ = 37

See below.

> Note that all three are technically legal[1,5], though only the last one
> is useful for doing interesting partial evaluation at macroexpansion time.

I disagree.  If I have some constant parameterizations in a large
system:

(defconstant airplane-height 400)
(defconstant skyscraper-height 5075)
(defconstant balloon-height 20000)

and then had a common macro that plugged them into a set of
formulae, then I think that it would be extremely unfriendly to
call out

Error: 20000 is too high to handle.

whereas a simple change would make it

Error: BALLOON-HEIGHT of 20000 is too high to handle.

making the parameterization much easier to debug, or
at least to track down the cause of the error.  But in a
system that aggressively replaces the constant at the
source level at  macroexpand-time, there is no way to
get the name of that symbolic constant.


Now of course, in order to do this, there is still something
missing from the spec: we already have CONSTANTP, but there is
no CONSTANT-VALUE - it had apparently been proposed and rejected
by X3J13, and I can guess that the reason why is the question of
what to do if a form is not constant (what should it return?
should it return two values, or should it call error if the form
is not constantp?)

That problem notwithstanding, if one limits the form argument
to only those forms for which CONSTANTP returns true, then it
is trivial to implement CONSTANT-VALUE using environments access -
assume the following definition for CONSTANTP, which implements
minimal semantics (e.g. it does not macroexpand, but that is
still within spec):

(defun constantp (form &optional environment)
  (typecase form
    (null t)
    (symbol
     (eq :constant (sys::variable-information form environment t)))
    (cons (and (eq (car form) 'quote)
	       (cdr form)
	       (null (cddr form))))
    (t t)))

Then CONSTANT-VALUE is equally trivial:

(defun constant-value (form &optional environment)
  (typecase form
    (null nil)
    (symbol
     (multiple-value-bind (kind valcell)
	 (sys::variable-information form environment t)
       (when (eq kind :constant)
	  valcell)))
    (cons (cadr form)) ;; Safe only if form has passed constantp.
    (t form)))

Given a function like this, I would be prepared to give you the
results of your example, modified as:

(defconstant +foo+ 37)

(defmacro hack (x &environment e)
  (if (constantp x e)
      `(format t "~a"
	       ,(with-output-to-string (s)
		  (format s "~
C: +foo+ var type = ~s, '+foo+ = ~s, type = ~s, +foo+ = ~s~%"
			  (type-of x) x (type-of (constant-value x e))
			  (constant-value x e))))
    `(format t "R: +foo+ type = ~s, +foo+ = ~s~%" (type-of ,x) ,x)))

(hack +foo+)

which results in

C: +foo+ var type = SYMBOL, '+foo+ = +FOO+, type = FIXNUM, +foo+ = 37

in Allegro CL 7.0.

More power (control) to the programmer!

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m38y71ge5e.fsf@javamonkey.com>
Duane Rettig <·····@franz.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> Duane Rettig <·····@franz.com> writes:
>> 
>> > Peter Seibel <·····@javamonkey.com> writes:
>> >
>> >> A few months ago I started (and dragged out to great length) a thread
>> >> in which I demonstrated my confusion about what the spec says about
>> >> evaluation and compilation environments vis a vis what happens when
>> >> they are separate. Eventually Duane Rettig got me straightened out.
>> >> 
>> >> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
>> >> *advantages* of separating the evaluation and compilation
>> >> environments. Duane mentioned something about "late binding" in that
>> >> thread but it was a bit to compressed for me to grok. Having thought
>> >> about it a bit it seems to me that one definitely wants the startup
>> >> environment and evaluation environment to be different (lest
>> >> COMPILE-FILE "contaminate" the startup environment). But, I don't see
>> >> any advantage to keeping the evaluation and compilation environments
>> >> separate. But there must be some. Duane? Anyone?
>> >
>> > Try this one:
>> >
>> > (defvar *spy*)
>> >
>> > (compile
>> >  (defun foo (x)
>> >    (macrolet ((bar ()
>> > 		(setq *spy* x)))
>> >      (bar))))
>> >
>> > (describe '*spy*)
>> >
>> > In many lisps, you'll get an error, and *spy* will never get assigned.
>> > However, in at least one lisp, you get some bleeding of compiler
>> > internals from the lexical value of x, which is in the compilation
>> > environment and was transferred to the evaluation environment.
>> >
>> > All of the lisps are conforming; the problem is that the code above
>> > is noncompliant.  (see the decription for macrolet, third paragraph
>> > in the macrolet bullet).  But the behavior of bleeding compiler
>> > internals is rather unfriendly.
>> 
>> Uh, this is a bit cryptic. While I'm happy to believe that this code
>> behaves in any of number of weird ways in various compliant
>> implementations, I don't see how this demonstrates an advantage for
>> keeping the compilation and evaluation environments separate. Can you
>> dumb it down for me?
>
> It's a simple example; work it through.  What are the likely
> "values" of x at the time of the macroexpansion?  

Undefined unless I'm missing something: per the MACROLET dictionary
entry:

  the consequences are undefined if the local macro definitions
  reference any local variable or function bindings that are visible
  in that lexical environment.

x is a local variable visible in the lexical environment, right? After
that I don't know where to go--I don't know how to analyze code with
undefined semantics.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <465253qai.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> Duane Rettig <·····@franz.com> writes:
> >> 
> >> > Peter Seibel <·····@javamonkey.com> writes:
> >> >
> >> >> A few months ago I started (and dragged out to great length) a thread
> >> >> in which I demonstrated my confusion about what the spec says about
> >> >> evaluation and compilation environments vis a vis what happens when
> >> >> they are separate. Eventually Duane Rettig got me straightened out.
> >> >> 
> >> >> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
> >> >> *advantages* of separating the evaluation and compilation
> >> >> environments. Duane mentioned something about "late binding" in that
> >> >> thread but it was a bit to compressed for me to grok. Having thought
> >> >> about it a bit it seems to me that one definitely wants the startup
> >> >> environment and evaluation environment to be different (lest
> >> >> COMPILE-FILE "contaminate" the startup environment). But, I don't see
> >> >> any advantage to keeping the evaluation and compilation environments
> >> >> separate. But there must be some. Duane? Anyone?
> >> >
> >> > Try this one:
> >> >
> >> > (defvar *spy*)
> >> >
> >> > (compile
> >> >  (defun foo (x)
> >> >    (macrolet ((bar ()
> >> > 		(setq *spy* x)))
> >> >      (bar))))
> >> >
> >> > (describe '*spy*)
> >> >
> >> > In many lisps, you'll get an error, and *spy* will never get assigned.
> >> > However, in at least one lisp, you get some bleeding of compiler
> >> > internals from the lexical value of x, which is in the compilation
> >> > environment and was transferred to the evaluation environment.
> >> >
> >> > All of the lisps are conforming; the problem is that the code above
> >> > is noncompliant.  (see the decription for macrolet, third paragraph
> >> > in the macrolet bullet).  But the behavior of bleeding compiler
> >> > internals is rather unfriendly.
> >> 
> >> Uh, this is a bit cryptic. While I'm happy to believe that this code
> >> behaves in any of number of weird ways in various compliant
> >> implementations, I don't see how this demonstrates an advantage for
> >> keeping the compilation and evaluation environments separate. Can you
> >> dumb it down for me?
> >
> > It's a simple example; work it through.  What are the likely
> > "values" of x at the time of the macroexpansion?  
> 
> Undefined unless I'm missing something: per the MACROLET dictionary
==^^^^^^^^^
> entry:

My question was "likely values".  "Undefined" is not a likely
value.  Yes, it is true that given an undefined situation, you
can't from the spec guarantee that your computer will not halt
and catch fire, because the behavior is undefined.  However, I
hope we can agree that it is not _likely_ that your computer will
hal and catch fire when you execute something undefined.  I'm trying
to move you past the issue of undefinedness to get an insight as
to _why_ it is undefined, and what the issue behind that undefinedness
is.

>   the consequences are undefined if the local macro definitions
>   reference any local variable or function bindings that are visible
>   in that lexical environment.
> 
> x is a local variable visible in the lexical environment, right?

Right, but _which_ lexical environment?

> After
> that I don't know where to go--I don't know how to analyze code with
> undefined semantics.

Well, you have that right not to proceed, but then you will not
be able to get an answer to the question of why the environments
may or may not be the same.  If you want to proceed, you must
take a trip into "likely" scenarios.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m34qhohp7y.fsf@javamonkey.com>
Duane Rettig <·····@franz.com> writes:

> Well, you have that right not to proceed, but then you will not be
> able to get an answer to the question of why the environments may or
> may not be the same. If you want to proceed, you must take a trip
> into "likely" scenarios.

Isn't there some way to explain why you guys chose to separate the
evaluation and compilation environment that doesn't rely on undefined
semantics. While these little puzzles are fun and all, what would you
say to a customer who comes to you and says, "Gosh, I hate the way you
guys combine the evaluation and compilation environments--I don't like
the way it make my wrap macro-writing macros in an EVAL-WHEN or put
them in a separate file from where I use them. Unless you convince me
there's some advantage to it that I'm missing, I'm gonna switch
implementations." I'm perfectly willing to stipulate that such a
customer is an unreasonable git. However I presume that you'd try to
explain to them why you guys made this choice rather than lose their
business. (In that other thread I mentioned you alluded to some
reasons having to do with "late binding" but I couldn't figure out
what you meant by that.)

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4wtuk3l77.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Well, you have that right not to proceed, but then you will not be
> > able to get an answer to the question of why the environments may or
> > may not be the same. If you want to proceed, you must take a trip
> > into "likely" scenarios.
> 
> Isn't there some way to explain why you guys chose to separate the
> evaluation and compilation environment that doesn't rely on undefined
> semantics.

I'm having a hard time understanding this question.  Your orignal
article in this thread asked about advantages of making a choice that
is specified to be undefined.  And now you are asking me to explain
it to you without going into undefined-teritory?

> While these little puzzles are fun and all, what would you
> say to a customer who comes to you and says, "Gosh, I hate the way you
> guys combine the evaluation and compilation environments--I don't like
> the way it make my wrap macro-writing macros in an EVAL-WHEN or put
> them in a separate file from where I use them. Unless you convince me
> there's some advantage to it that I'm missing, I'm gonna switch
> implementations." I'm perfectly willing to stipulate that such a
> customer is an unreasonable git. However I presume that you'd try to
> explain to them why you guys made this choice rather than lose their
> business.

I don't think I care to discuss this part here.  Every design decision
we make is made with the eye toward maximizing our customers' comfort
and minimizing their pain by improving our product.  To a large extent,
I believe that we succeed (as, I believe, do most other CL vendors).
How I would respond to an unhappy customer really has no place in this
forum.

Perhaps your question is a deeper one, and you can reword it so as
not to include business issues?

> (In that other thread I mentioned you alluded to some
> reasons having to do with "late binding" but I couldn't figure out
> what you meant by that.)

Google seems to have changed its interface, and I'm not yet used
to the new searching mechanism.  Can you give me a link, so I can
get back into context of that thread?  I have an idea of what I
might have been thinking, but I want to be sure...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m3acrgg2yt.fsf@javamonkey.com>
Duane Rettig <·····@franz.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> Duane Rettig <·····@franz.com> writes:
>> 
>> > Well, you have that right not to proceed, but then you will not
>> > be able to get an answer to the question of why the environments
>> > may or may not be the same. If you want to proceed, you must take
>> > a trip into "likely" scenarios.
>> 
>> Isn't there some way to explain why you guys chose to separate the
>> evaluation and compilation environment that doesn't rely on
>> undefined semantics.
>
> I'm having a hard time understanding this question.  Your orignal
> article in this thread asked about advantages of making a choice that
> is specified to be undefined.  And now you are asking me to explain
> it to you without going into undefined-teritory?

Well there are lots of choices left up to Common Lisp implementors
where the different choices have benefits and drawbacks even for
conforming programs. For instance most implementors chose to provide
GC. And many implementations provide a to-machine-code compiler.
Presumably describing the benefits of those choices doesn't require a
discussion of how code with no defined semantics behaves.

Now this choice is obviously different in many ways from those choices
so maybe it's *not* possible in this case. Anyway, what I was hoping
was that someone would help me complete this sentence:

  "When I implemented Common Lisp, I separated the compilation and
  evaluation environments because ..."

Possible completions might be of the form:

  "... it made my implementation simpler."

  "... it made my implementation faster."

  "... it allowed me to give better error messages."

Now, another possible completion might be:

  "... it allowed me to provide a meaningful semantics for X, which is
  undefined in the language standard."

But that's only one of the possibilities. 

>> (In that other thread I mentioned you alluded to some
>> reasons having to do with "late binding" but I couldn't figure out
>> what you meant by that.)
>
> Google seems to have changed its interface, and I'm not yet used
> to the new searching mechanism.  Can you give me a link, so I can
> get back into context of that thread?  I have an idea of what I
> might have been thinking, but I want to be sure...

Message 8 in this thread:

 <http://groups-beta.google.com/group/comp.lang.lisp/browse_frm/thread/170d01370010f113>

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4mzvggw1i.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> Duane Rettig <·····@franz.com> writes:
> >> 
> >> > Well, you have that right not to proceed, but then you will not
> >> > be able to get an answer to the question of why the environments
> >> > may or may not be the same. If you want to proceed, you must take
> >> > a trip into "likely" scenarios.
> >> 
> >> Isn't there some way to explain why you guys chose to separate the
> >> evaluation and compilation environment that doesn't rely on
> >> undefined semantics.
> >
> > I'm having a hard time understanding this question.  Your orignal
> > article in this thread asked about advantages of making a choice that
> > is specified to be undefined.  And now you are asking me to explain
> > it to you without going into undefined-teritory?
> 
> Well there are lots of choices left up to Common Lisp implementors
> where the different choices have benefits and drawbacks even for
> conforming programs. For instance most implementors chose to provide
> GC. And many implementations provide a to-machine-code compiler.
> Presumably describing the benefits of those choices doesn't require a
> discussion of how code with no defined semantics behaves.

But we're not talking about code with _no_ defined semantics.  I'm
trying to lead you into seeing what _is_ defined.  I'm taking you
through a swamp by showing you the stepping stones, and although
you have a right not to go through, you're telling me that the
reason you don't want to go through is because "it's a swamp."
Well, right you are...

> Now this choice is obviously different in many ways from those choices
> so maybe it's *not* possible in this case.

Not so different.  You mentioned GC being undefined.  Does that mean
we can't talk about the intrinsics of heap usage that are invariant
regardless of whether a gc is provided?  What happens if we do
talk about it and find that our heap has run out?  Should we have
refrained from talking about heap allocation at all, or can we get
away with just talking about it up to the point where the heap is
going to run out?

> Anyway, what I was hoping
> was that someone would help me complete this sentence:
> 
>   "When I implemented Common Lisp, I separated the compilation and
>   evaluation environments because ..."
> 
> Possible completions might be of the form:
> 
>   "... it made my implementation simpler."

Certainly not :-)

>   "... it made my implementation faster."

Probably not...

>   "... it allowed me to give better error messages."

Possibly not - but perhaps fewer in the long run, for conforming code
or at least for code that conforms to the implementation's extensions.

> Now, another possible completion might be:
> 
>   "... it allowed me to provide a meaningful semantics for X, which is
>   undefined in the language standard."

Heh; if you're trying to get me to equate X with Environments Access,
then you're out of luck; the decision had been made toward separate
compilation and evaluation environments long before that.

> But that's only one of the possibilities. 
> 
> >> (In that other thread I mentioned you alluded to some
> >> reasons having to do with "late binding" but I couldn't figure out
> >> what you meant by that.)
> >
> > Google seems to have changed its interface, and I'm not yet used
> > to the new searching mechanism.  Can you give me a link, so I can
> > get back into context of that thread?  I have an idea of what I
> > might have been thinking, but I want to be sure...
> 
> Message 8 in this thread:
> 
>  <http://groups-beta.google.com/group/comp.lang.lisp/browse_frm/thread/170d01370010f113>

OK, thanks for this.  Actually, looking at the specific place where
I made the claim:
http://groups-beta.google.com/group/comp.lang.lisp/msg/a922a8753d950068
I think I gave a fairly complete answer, sans actual example:

! Now, if you can see the issues involved here, the burning question
! might be "but why _not_ merge the compilation and evaluation
! environments, and thus allow macros to be compiled as they appear
! in the file?" and the answer is simply: "late binding". I don't
! have time to work up a practical example, but consider that compiling
! a baz definition and expanding out the foo macro forces you to recompile
! that definition if you redefine foo but intend to use baz again. Keeping
! things uncompiled allows a minimum of (eval-when (:compile-toplevel ...) ...)
! forms wrapping macros, or a minimal ordering requirement on the macro
! definitions.

Note that the stepping stones of CL, namely 3.2.2.3, require that if baz
calls foo in the same file (and I am presuming as a worst-case that the
same semantics apply to macro definitions as to functions, since macros
have macro-function definitions) that it is always the same file.
But there is no such restriction (i.e. optimization) on baz if
it calls foo and foo had been defined elsewhere, and is either being
shadowed in this file or may even be defined twice, once for each
invocation of baz from yet other files.  Of course, this would depend
on yet another aspect that is explicitly undefined, i.e. where 3.2.3.1.1
states whether baz's definition will last beyond the compilation of the
file that held it (Caution, we're in the swamp again).  But consider the
highly useful extension that might be made, where the compilation
environment has its scope extended to the edge of the outer
with-compilation-unit (or to the innermost one that turns on the
 :override argument).  If you put on some high boots, you would be
able to wade in that swamp even without stepping stones...

In simpler terms, wouldn't it be nice if the macro definitions from
one file could be shared with another without having to load either,
just by saying

 (with-compilation-unit ()
    (compile-file "foo.cl")
    (compile-file "bar.cl"))

?

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Alan Crowe
Subject: hallucinating quote
Date: 
Message-ID: <867jmkf77l.fsf_-_@cawtech.freeserve.co.uk>
Duane's code gives me hallucinations.
First

(compile '(defun foo(x) stuff))

isn't right. COMPILE takes a function name as its argument,
either a symbol or (SETF symbol).
Not only is it wrong, it isn't what Duane posted.

Duane also didn't post

(compile (defun foo (x)
  (macrolet ((bar ()
              '(setq *spy* x)))
    (bar))))

The quote is due to eating grapefruit and having a splash on
my glasses. It makes BAR expand to (SETQ *SPY* X). Duane's
code expands BAR to be the value assigned.

Is it just me, or are other readers of this thread being
blinded by overwhelming expectations about the code they are reading?

Alan Crowe
Edinburgh
Scotland
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <87d5wd9exp.fsf@qrnik.zagroda>
Peter Seibel <·····@javamonkey.com> writes:

> While I'm happy to believe that this code behaves in any of number
> of weird ways in various compliant implementations, I don't see how
> this demonstrates an advantage for keeping the compilation and
> evaluation environments separate.

For me more interesting is the question why the choices of using the
same or separate environments are up to the implementation, instead
of having well-defined rules for such a fundamental issue.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m33bx9i6bk.fsf@javamonkey.com>
Ingvar <······@hexapodia.net> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> A few months ago I started (and dragged out to great length) a thread
>> in which I demonstrated my confusion about what the spec says about
>> evaluation and compilation environments vis a vis what happens when
>> they are separate. Eventually Duane Rettig got me straightened out.
>> 
>> Now I'm thinking about EVAL-WHEN and am curious to hear more about the
>> *advantages* of separating the evaluation and compilation
>> environments. Duane mentioned something about "late binding" in that
>> thread but it was a bit to compressed for me to grok. Having thought
>> about it a bit it seems to me that one definitely wants the startup
>> environment and evaluation environment to be different (lest
>> COMPILE-FILE "contaminate" the startup environment). But, I don't see
>> any advantage to keeping the evaluation and compilation environments
>> separate. But there must be some. Duane? Anyone?
>
> One reason I can see is if you have a long-running application (with a
> bundled compiler) compile its next version in parallel with running,
> you would want to avoid leaking type information from the "to-be"
> runtime environment to the "is" runtime environment.
>
> I can't see a way around that other than separating evaluation and
> compilation environments.

I'm not sure that's right. Perhaps but let's make sure we have our
terminology straight. Per section 3.2.1, there are three environments
to consider when talking about COMPILE-FILE:

  The startup environment is the environment of the Lisp image from
  which the compiler was invoked.

  The compilation environment is maintained by the compiler and is
  used to hold definitions and declarations to be used internally by
  the compiler. Only those parts of a definition needed for correct
  compilation are saved. The compilation environment is used as the
  environment argument to macro expanders called by the compiler. It
  is unspecified whether a definition available in the compilation
  environment can be used in an evaluation initiated in the startup
  environment or evaluation environment.

  The evaluation environment is a run-time environment in which macro
  expanders and code specified by eval-when to be evaluated are
  evaluated. All evaluations initiated by the compiler take place in
  the evaluation environment.

A fourth environment comes into play when the FASL is loaded:

  The run-time environment is the environment in which the program
  being compiled will be executed.

Section 3.2.1 then goes on to describe the relationship betwen the
three environments present at compile time:

  The compilation environment inherits from the evaluation
  environment, and the compilation environment and evaluation
  environment might be identical. The evaluation environment inherits
  from the startup environment, and the startup environment and
  evaluation environment might be identical.

I agree that you want to keep the startup and evaluation environment
distinct so stuff that happens during compilation has no affect on the
environment from which COMPILE-FILE was invoked. But I don't see how
making the evaluation environment and the compilation environment
identical leads to leaking back to the application.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Bruno Haible
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <cruole$cpn$1@laposte.ilog.fr>
Peter Seibel wrote:
> *advantages* of separating the evaluation and compilation environments ?

The most important advantage is that it helps guaranteeing that the
code being executed is the one that the programmer views in the editor.

There are different situations when the running code is different from
what the programmer thinks is running, and in each of these situations
the programmer is losing time:

  - When there are so many copies of the source files in your environment
    that you end up looking at and modifying the wrong copy.

  - When the compiler has incorporated some knowledge from its compilation
    environment, such as an INLINE function definition or the value of a
    constant, that is not present in the source files. (For example, if
    you just removed the function definition or changed the value of the
    constant.)

  - Any kind of compiler bug :-)

Since in CL the definitions in the compilation environment can be used
by COMPILE-FILE, any code that changes the compilation environment is
a side effect on future COMPILE-FILE invocations. Scheme tells us that
side effects are bad. Therefore it is desirable if the side effects of
a COMPILE-FILE invocation on the compilation environment can be minimized.

                         Bruno
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m3d5wdgfcc.fsf@javamonkey.com>
Bruno Haible <·····@clisp.org> writes:

> Since in CL the definitions in the compilation environment can be
> used by COMPILE-FILE, any code that changes the compilation
> environment is a side effect on future COMPILE-FILE invocations.
> Scheme tells us that side effects are bad. Therefore it is desirable
> if the side effects of a COMPILE-FILE invocation on the compilation
> environment can be minimized.

Wow. So you're saying that changes to the compilation environment from
one invocation of COMPILE-FILE stick around and affect future
invocations of COMPILE-FILE? That's not at all what I expected after
reading this from Section 3.2.1:

  The compilation environment inherits from the evaluation
  environment, and the compilation environment and evaluation
  environment might be identical. The evaluation environment inherits
  from the startup environment, and the startup environment and
  evaluation environment might be identical.

Given that the startup environment "is the environment of the Lisp
image from which the compiler was invoked", I read that to mean that
at the very beginning of each call to COMPILE-FILE the startup,
evaluation, and compilation environments all contain the same stuff.
Then the evaluation and compilation environments (or environment if
they are identical) would be modified as a result of stuff that
happens during the call to COMPILE-FILE.

But, if I understand you correctly, you're saying that the compilation
environment starts out with whatever it inherits from the startup
environment (by way of the evaluation environment) *plus* some other
stuff left over from previous invocations of COMPILE-FILE. Is that
what you're saying? And if so, how does that jibe with 3.2.1?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Bruno Haible
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <cs14va$h59$1@laposte.ilog.fr>
Peter Seibel wrote:
>
> Wow. So you're saying that changes to the compilation environment from
> one invocation of COMPILE-FILE stick around and affect future
> invocations of COMPILE-FILE?

Yes. That's how it works in many CL implementations, and
EVAL-WHEN COMPILE is known to amplify these effects.

For example, take these two files:
====================== bar.lisp =======================
(defun make-buffer ()
  (make-array (get-bufsize)))

(defvar *bufsize* 20)
(defun get-bufsize ()
  *bufsize*)
====================== foo.lisp =======================
(eval-when (compile load eval)
  (declaim (inline get-bufsize))
  (defun get-bufsize () 512))

(defconstant *old-bufsiz* #.(get-bufsize))
=======================================================

If you compile them separately, bar.lisp behaves as expected:

    $ sbcl
    * (compile-file "foo.lisp")
    * (quit)
    $ sbcl
    * (compile-file "bar.lisp")
    * (quit)
    $ sbcl
    * (load "bar")
    * (length (make-buffer))
    20

But if you compile bar.lisp in an environment that had compiled
foo.lisp earlier - in the same session -, bar.lisp will behave
at runtime in a way that is not consistent with the source code:

    $ sbcl
    * (compile-file "foo.lisp")
    * (compile-file "bar.lisp")
    * (quit)
    $ sbcl
    * (load "bar")
    * (length (make-buffer))
    512

> That's not at all what I expected after reading this from
> Section 3.2.1:
>
>  The compilation environment inherits from the evaluation
>  environment, and the compilation environment and evaluation
>  environment might be identical. The evaluation environment inherits
>  from the startup environment, and the startup environment and
>  evaluation environment might be identical.

I think the first sentence means that whether or not the second
COMPILE-FILE calls sees the side effects of the first COMPILE-FILE
call, is implementation-dependent. The second sentence means that
in an implementation with multiple windows containing each a REP-loop,
it is implementation-dependent whether a definition made in one of
these REP-loops can be used in one of the other REP-loops.

> But, if I understand you correctly, you're saying that the compilation
> environment starts out with whatever it inherits from the startup
> environment (by way of the evaluation environment) *plus* some other
> stuff left over from previous invocations of COMPILE-FILE.

That's the case if the compilation environment and the evaluation
environment are the same. If, however, a fresh compilation environment
is created at each invocation of COMPILE-FILE or WITH-COMPILATION-UNIT,
then there will be less side effects from one compilation to the next.

               Bruno
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m3llazepy9.fsf@javamonkey.com>
Bruno Haible <·····@clisp.org> writes:

> Peter Seibel wrote:

>> That's not at all what I expected after reading this from Section
>> 3.2.1:
>>
>>  The compilation environment inherits from the evaluation
>>  environment, and the compilation environment and evaluation
>>  environment might be identical. The evaluation environment
>>  inherits from the startup environment, and the startup environment
>>  and evaluation environment might be identical.
>
> I think the first sentence means that whether or not the second
> COMPILE-FILE calls sees the side effects of the first COMPILE-FILE
> call, is implementation-dependent. The second sentence means that
> in an implementation with multiple windows containing each a REP-loop,
> it is implementation-dependent whether a definition made in one of
> these REP-loops can be used in one of the other REP-loops.

Hmmm. I read the second sentence as saying that the effect of code
that runs during macro expansions performed by COMPILE-FILE (which run
in the evaluation environment) may or may not be visible in the REPL
from which COMPILE-FILE was invoked. If the evaluation and startup
environments are identical they will be, if they are different they
will not. Which is a whole 'nother kettle of worms.

>> But, if I understand you correctly, you're saying that the
>> compilation environment starts out with whatever it inherits from
>> the startup environment (by way of the evaluation environment)
>> *plus* some other stuff left over from previous invocations of
>> COMPILE-FILE.
>
> That's the case if the compilation environment and the evaluation
> environment are the same.

This is the bit I don't get. Suppose I implement COMPILE-FILE so it
copies the environment from which it is invoked (i.e. it copies the
startup environment). Then while it runs it uses that one environment
as both the compilation environment (to stash macro definitions, etc.)
and th evaluation environment (to run macro expanders). Now assume at
the end of COMPILE-FILE I throw away that environment. The compilation
and evaluation environments are identical but you don't get any
leakage from one invocation of COMPILE-FILE to another

> If, however, a fresh compilation environment is created at each
> invocation of COMPILE-FILE or WITH-COMPILATION-UNIT, then there will
> be less side effects from one compilation to the next.

That seems to me orthogonal to the question of whether the compilation
and evaluation environments are identical.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4d5wb68cm.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Bruno Haible <·····@clisp.org> writes:
> 
> > Peter Seibel wrote:
> 
> >> But, if I understand you correctly, you're saying that the
> >> compilation environment starts out with whatever it inherits from
> >> the startup environment (by way of the evaluation environment)
> >> *plus* some other stuff left over from previous invocations of
> >> COMPILE-FILE.
> >
> > That's the case if the compilation environment and the evaluation
> > environment are the same.
> 
> This is the bit I don't get. Suppose I implement COMPILE-FILE so it
> copies the environment from which it is invoked (i.e. it copies the
> startup environment). Then while it runs it uses that one environment
> as both the compilation environment (to stash macro definitions, etc.)
> and th evaluation environment (to run macro expanders). Now assume at
> the end of COMPILE-FILE I throw away that environment. The compilation
> and evaluation environments are identical but you don't get any
> leakage from one invocation of COMPILE-FILE to another

See 3.2.3.1.1, last paragraph.  The tie-in happens there, but note
especially that it is the compilation environment that one would
save over if that were the design choice, since that is where the
definitions are stored.
 
> > If, however, a fresh compilation environment is created at each
> > invocation of COMPILE-FILE or WITH-COMPILATION-UNIT, then there will
> > be less side effects from one compilation to the next.
> 
> That seems to me orthogonal to the question of whether the compilation
> and evaluation environments are identical.

They are orthogonal, in a yoked oxen sort of way.

By the way, Bruno's example in Allegro CL returns 20, and always has.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Seibel
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <m3zmzfd55f.fsf@javamonkey.com>
Duane Rettig <·····@franz.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> Bruno Haible <·····@clisp.org> writes:
>> 
>> > Peter Seibel wrote:
>> 
>> >> But, if I understand you correctly, you're saying that the
>> >> compilation environment starts out with whatever it inherits
>> >> from the startup environment (by way of the evaluation
>> >> environment) *plus* some other stuff left over from previous
>> >> invocations of COMPILE-FILE.
>> >
>> > That's the case if the compilation environment and the evaluation
>> > environment are the same.
>> 
>> This is the bit I don't get. Suppose I implement COMPILE-FILE so it
>> copies the environment from which it is invoked (i.e. it copies the
>> startup environment). Then while it runs it uses that one
>> environment as both the compilation environment (to stash macro
>> definitions, etc.) and th evaluation environment (to run macro
>> expanders). Now assume at the end of COMPILE-FILE I throw away that
>> environment. The compilation and evaluation environments are
>> identical but you don't get any leakage from one invocation of
>> COMPILE-FILE to another
>
> See 3.2.3.1.1, last paragraph.  The tie-in happens there, but note
> especially that it is the compilation environment that one would
> save over if that were the design choice, since that is where the
> definitions are stored.

I agree that gives implementors the lattitude to carry over the
compilation environment from COMPILE-FILE to COMPILE-FILE. But I don't
see how that choice implies that the compilation and evaluation
environments can't be identical. As I see it an implementtion has
several choices:

 A. Use same environment as compilation and evaluation environments or
    not.

 B. Use same environment as startup and evaluation environments or
    not.

 C. Keep compilation environment around between calls to compiler or
    not.

If I understand you and Bruno correctly, you're claiming there's if
the choice in A is to use the same environment then that dictates the
choice in C, namely that you must then keep the compilation
environment between compilations. Is that what you're saying? If so,
I'm still not getting why.

On a, perhaps tangential note, I'm not sure how to reconcile the claim
that the compilation environment "inherits" from the startup
environment (by way of the evaluation environment if they are not the
same) and the possibility that the compilation environment can contain
information stashed by previous compilations. Which takes precedence
if information in the compilation environment from a previous compile
conflicts with information inherited from the startup environment of a
new compile?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4hdlnot1c.fsf@franz.com>
Peter Seibel <·····@javamonkey.com> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Peter Seibel <·····@javamonkey.com> writes:
> >
> >> Bruno Haible <·····@clisp.org> writes:
> >> 
> >> > Peter Seibel wrote:
> >> 
> >> >> But, if I understand you correctly, you're saying that the
> >> >> compilation environment starts out with whatever it inherits
> >> >> from the startup environment (by way of the evaluation
> >> >> environment) *plus* some other stuff left over from previous
> >> >> invocations of COMPILE-FILE.
> >> >
> >> > That's the case if the compilation environment and the evaluation
> >> > environment are the same.
> >> 
> >> This is the bit I don't get. Suppose I implement COMPILE-FILE so it
> >> copies the environment from which it is invoked (i.e. it copies the
> >> startup environment). Then while it runs it uses that one
> >> environment as both the compilation environment (to stash macro
> >> definitions, etc.) and th evaluation environment (to run macro
> >> expanders). Now assume at the end of COMPILE-FILE I throw away that
> >> environment. The compilation and evaluation environments are
> >> identical but you don't get any leakage from one invocation of
> >> COMPILE-FILE to another
> >
> > See 3.2.3.1.1, last paragraph.  The tie-in happens there, but note
> > especially that it is the compilation environment that one would
> > save over if that were the design choice, since that is where the
> > definitions are stored.
> 
> I agree that gives implementors the lattitude to carry over the
> compilation environment from COMPILE-FILE to COMPILE-FILE. But I don't
> see how that choice implies that the compilation and evaluation
> environments can't be identical.

I don't think either of us are saying that.  At least, I'm not. In
fact, the two choices are in fact that the compilation environment
is either identical or not identical to the evaluation environment.

However, if one introduces the possibility of extending the
compilation environment beyond a compile-file (say, to the end of
a compilation-unit), then what _must_ be saved is any definitions
that are present that are required to be in the compilation
environment.  If the evaluation environment is implemented to have
more than just those required definitions, then it is more efficient
to separate the two, and to only keep the compilation environment
minimal, so as not to be as large as if it were merged with the
evaluation environment.

> As I see it an implementtion has
> several choices:
> 
>  A. Use same environment as compilation and evaluation environments or
>     not.
> 
>  B. Use same environment as startup and evaluation environments or
>     not.
> 
>  C. Keep compilation environment around between calls to compiler or
>     not.
> 
> If I understand you and Bruno correctly, you're claiming there's if
> the choice in A is to use the same environment then that dictates the
> choice in C, namely that you must then keep the compilation
> environment between compilations. Is that what you're saying? If so,
> I'm still not getting why.

I'm certainly not saying that.  Perhaps Bruno did, but I don't recall
seeing it.  I'm actually assuming that you've made a typo somewhere,
here, because if not, then you're saying "if you choose to keep
compilation environments around, then you must keep compilation
environments around" which is of course trivially true.  But if there
is a typo or braino here somewhere, then whatever it is you were
intending to say likely cannot be true, since I'm not saying you _must_
keep anything.  My motivation for separate compilation and evaluation
environments is to keep the part that must be manipulated (i.e. the
definitions within the compilation environment) from having to be
very large.  That's all.

> On a, perhaps tangential note, I'm not sure how to reconcile the claim
> that the compilation environment "inherits" from the startup
> environment (by way of the evaluation environment if they are not the
> same) and the possibility that the compilation environment can contain
> information stashed by previous compilations. Which takes precedence
> if information in the compilation environment from a previous compile
> conflicts with information inherited from the startup environment of a
> new compile?

If you look up the glossary term for inherit, there are three definitions,
and only the first can possibly apply; this one is much more general
and pliable.  In order to get the relationships, you must first
de-CLOSsify your mind toward inheritance; it is true that the lexical
portion of an environment is heirarchical, but the global portion is
heap-like, and fully dynamic (hence it is described as dynamic).  So
in this case you could think of "A inherits from B" as "B gave birth
to A".  It may be that the entire environment is copied upon
birth (this would be implausible; copying an entire heap is pretty
expensive) and it is more likely that the lookup of bindings in
one environment might have some fall-back lookup in the "parent"
environment, but only if bindings weren't found in the first one.

The issue of precedence over conflicting information is a hard one, and
it must be solved (i.e. well-defined in simple terms) before any
implementation actually performs this particular extension.  I would
think that the behaviors in this kind of situation should be similar
when done in compiler environments as it is when it is done in the
runtime environments.  So, for example, if I were to extend
with-compilation-unit to allow the following:

(with-compilation-unit
  (compile-file "foo.cl")
  (compile-file "bar.cl"))

with one environment, then I'd want to make my decisions based on
and as close as possible to what behaviors I would get when I do:

  (compile-file "foo.cl")
  (load "foo.fasl")
  (compile-file "bar.cl")

because that would be the concept of least surprise and it owuld be
easiest to accept.


-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Don Geddis
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <873bx6legl.fsf@sidious.geddis.org>
Duane Rettig <·····@franz.com> wrote on 12 Jan 2005 02:1:
> So, for example, if I were to extend with-compilation-unit to allow the
> following:
> (with-compilation-unit
>   (compile-file "foo.cl")
>   (compile-file "bar.cl"))
> with one environment, then I'd want to make my decisions based on
> and as close as possible to what behaviors I would get when I do:
>   (compile-file "foo.cl")
>   (load "foo.fasl")
>   (compile-file "bar.cl")
> because that would be the concept of least surprise and it owuld be
> easiest to accept.

It would seem to me that the translation of "least surprise" would be
something more like
        (unix:cat '("foo.cl" "bar.cl") "new-file.cl")
        (compile-file "new-file.cl")
i.e., treat it as one continuous source file.

Wouldn't your translation add the confusion of having a load time occur?
Which would be noticed by any (EVAL-WHEN (:LOAD-TOPLEVEL) ...) code in the
foo.cl source file?

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
From: Duane Rettig
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <4is628omq.fsf@franz.com>
Don Geddis <···@geddis.org> writes:

> Duane Rettig <·····@franz.com> wrote on 12 Jan 2005 02:1:
> > So, for example, if I were to extend with-compilation-unit to allow the
> > following:
> > (with-compilation-unit
> >   (compile-file "foo.cl")
> >   (compile-file "bar.cl"))
> > with one environment, then I'd want to make my decisions based on
> > and as close as possible to what behaviors I would get when I do:
> >   (compile-file "foo.cl")
> >   (load "foo.fasl")
> >   (compile-file "bar.cl")
> > because that would be the concept of least surprise and it owuld be
> > easiest to accept.
> 
> It would seem to me that the translation of "least surprise" would be
> something more like
>         (unix:cat '("foo.cl" "bar.cl") "new-file.cl")
>         (compile-file "new-file.cl")
> i.e., treat it as one continuous source file.

Yes, you're probably right.  I like your analogue better than mine
for causing the _very_ least surprise.  However, the motivation for
my analogue is defsystem.  Most of the time defsystems are coded to
either compile all files and then load them, or compile each file
and load it before compiling the next file (or, alternatively, a
specification might be set up of dependencies of a particular file
on either the compilation or loading of another file).  Each case has
to be carefully considered, and the files set up in such a way as is
appropriate for the style in which is intended for the defsystem to
load the system.  My eventual goal for such extensions would be
to enable the programmer to not have to think quite as hard about
what dependencies each file have on the way they are loaded.  I
don't think so much of my ability to eliminate the need to think
about these entirely...

> Wouldn't your translation add the confusion of having a load time occur?
> Which would be noticed by any (EVAL-WHEN (:LOAD-TOPLEVEL) ...) code in the
> foo.cl source file?

CL handles some of these issues by mandate; for example, per 3.2.2.3,
constants and types (notably, classes) must have similar values in a
compile-file situation as at run-time (e.g. at the point at load-time
when the same place in the file is encountered equivalent to the same
place in the source code that had been enccountered at compile-time).
There may be similar such issues with such an extension, but of course
I would want to keep them to a minimum...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Bruno Haible
Subject: Re: Separating evaluation and compilation environments.
Date: 
Message-ID: <cs1hg1$p03$1@laposte.ilog.fr>
Duane Rettig wrote:
>
> By the way, Bruno's example in Allegro CL returns 20 

Likewise for CLISP, of course :-)

           Bruno