From: Peter Seibel
Subject: Another environment question
Date: 
Message-ID: <m3smn79cvz.fsf@javamonkey.com>
So I thought I understood the distinction between the compilation,
evaluation, and runtime environments until this experiment didn't work
out the way I expected. Can anyone explain what I'm missing:

I create two files file1.lisp and file2.lisp as shown here:

;;; file1.lisp

(defpackage #:test-env (:use #:common-lisp))

(in-package #:test-env)

(defconstant +foo+ 10)

(defmacro foo (arg &environment env)
  `(format t
           "~s is~:[ NOT~;~] constant in passed in env; it is~:[ NOT~;~] constant in null env."
           ',arg ,(constantp arg env) ,(constantp arg)))

(defun bar () (foo +foo+))


;;; file2.lisp

(in-package #:test-env)

(defun baz () (foo +foo+))


Now I expect that if I (compile-file "file1.lisp") that because the
DEFCONSTANT is a top-level form that +FOO+ will be seen as a constant
form in the compilation environment. Thus when the compiler invokes
FOO (in order to compile BAR) it will pass to the &environment
parameter, an environment where +foo+ will be constantp.

If I then LOAD file1.fasl, I'd expect (test-env::bar) to print either:

  TEST-ENV::+FOO+ is constant in passed in env; it is NOT constant in null env.

or

  TEST-ENV::+FOO+ is constant in passed in env; it is constant in null env.

I.e. +FOO+ should be constantp in the compilation environment that
will be passed to FOO when compiling BAR but may or may not show up as
constantp in the evaluation environment in which FOO is actually
evaluated since that environment may be distinct from the compilation
environment.

I further expect that if, after compiling and loading file1, I compile
and load file2, (test-env::baz) will print:

  TEST-ENV::+FOO+ is constant in passed in env; it is constant in null env.

since the startup environment for the compilation of file2 included
the definitions loaded from file1.lisp in which +FOO+ is constantp.

My expectations for what happens after compiling and loading file2 and
running BAZ were met. However, several CL implementations I tried said
that +FOO+ was NOT constantp in the environment passed to FOO when
compiling BAR. I assume I am misunderstanding something about how this
is supposed to work or this test isn't testing what I think it is.

-Peter

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

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

From: Barry Margolin
Subject: Re: Another environment question
Date: 
Message-ID: <9Q67b.611$mD.283@news.level3.com>
In article <··············@javamonkey.com>,
Peter Seibel  <·····@javamonkey.com> wrote:
>My expectations for what happens after compiling and loading file2 and
>running BAZ were met. However, several CL implementations I tried said
>that +FOO+ was NOT constantp in the environment passed to FOO when
>compiling BAR. I assume I am misunderstanding something about how this
>is supposed to work or this test isn't testing what I think it is.

I think some implementations of CONSTANTP only recognize literals, not
variables declared with DEFCONSTANT.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Peter Seibel
Subject: Re: Another environment question
Date: 
Message-ID: <m3k78j9c9l.fsf@javamonkey.com>
Barry Margolin <··············@level3.com> writes:

> In article <··············@javamonkey.com>,
> Peter Seibel  <·····@javamonkey.com> wrote:
> >My expectations for what happens after compiling and loading file2 and
> >running BAZ were met. However, several CL implementations I tried said
> >that +FOO+ was NOT constantp in the environment passed to FOO when
> >compiling BAR. I assume I am misunderstanding something about how this
> >is supposed to work or this test isn't testing what I think it is.
> 
> I think some implementations of CONSTANTP only recognize literals, not
> variables declared with DEFCONSTANT.

Should such implementations be considered non-conformant (in this
area), given that the definition of CONSTANTP includes:


* Constant variables, such as keywords, symbols defined by Common Lisp
  as constant (such as nil, t, and pi), and symbols declared as
                                            ^^^^^^^^^^^^^^^^^^^
  constant by the user in the indicated environment using defconstant
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
  are always considered constant forms and must be recognized as such
  by constantp.

?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Rob Warnock
Subject: Re: Another environment question
Date: 
Message-ID: <E3ydncWvpN2rKMCiXTWc-g@speakeasy.net>
Peter Seibel  <·····@javamonkey.com> wrote:
+---------------
| Barry Margolin <··············@level3.com> writes:
| > I think some implementations of CONSTANTP only recognize literals, not
| > variables declared with DEFCONSTANT.
| 
| Should such implementations be considered non-conformant (in this
| area), given that the definition of CONSTANTP includes:
| 
| 
| * Constant variables, such as keywords, symbols defined by Common Lisp
|   as constant (such as nil, t, and pi), and symbols declared as
|                                             ^^^^^^^^^^^^^^^^^^^
|   constant by the user in the indicated environment using defconstant
|   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
|   are always considered constant forms and must be recognized as such
|   by constantp.
+---------------

I don't know if this is the same as the problem you're having, but I
ran into a similar problem[1] with DEFCONSTANT+CONSTANTP with CMUCL
during which I discovered to my chagrin that it appears conforming
for an implementation to report that a symbol was CONSTANTP at compile
time (due to DEFCONSTANT) yet *not* make it's value accessible at
compile time. A careful reading of CLHS "Macro DEFCONSTANT" eventually
showed why:

	If a defconstant form appears as a top level form, the compiler
	must recognize that name names a constant variable.

So far so good, but then in the next sentence:

	An implementation may choose to evaluate the value-form at
	compile time, load time, or both. 

Thus, an implementation is explicitly permitted to *not* evaluate the
value-form at compile time, and CMUCL doesn't -- though it *does* report
the symbol to be CONSTANTP (as required). So you end up with a "constant"
that can't be usefully constant-folded by a user macro at compile time.[2]


-Rob

[1] Using a draft new version of Tim Bradshaw's HTOUT, which worked fine
    at his site but broke at mine.

[2] Consider a macro that wants to compute a result at compile time iff
    all of its arguments are CONSTANTP, otherwise it will emit code to
    be evaluated at run-time [or perhaps load-time]. Using the simple
    test (EVERY #'CONSTANTP args) is not sufficient [at least not in an
    implementation such as CMUCL]. Instead, you need a more complex test
    to be safe:

	(every (lambda (x) (and (constantp x)
				(or (keywordp x) (not (symbolp x)))))
	       args)

    Or if some of your DEFCONSTANTs are in (EVAL-WHEN (:COMPILE-TOPLEVEL)...)
    forms *and* you really, really want to pick those up [even if you
    can't get the DEFCONSTANTs that aren't in such forms] you might want
    to go to the trouble of doing this:

	(every (lambda (x) (and (constantp x)
				(or (not (symbolp x)) (boundp x))))
	       args)

    Just remember to wrap the propor pieces of the macro in the proper
    EVAL-WHENs...

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607