From: Raymond Toy
Subject: locally and let?
Date: 
Message-ID: <4nog15h6c6.fsf@rtp.ericsson.se>
In the latest release of series, series fails to work on MCL because
series use of LOCALLY.  In cmulisp and clisp, LOCALLY gets macroexpanded
into a LET, so series never sees LOCALLY forms.

Is there anything wrong with doing this?  That is, converting a

(locally declares forms)

into

(let () declares forms)

It seems ok to me, but I'm not sure.

Thanks,

Ray

From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m28zs871i8.fsf@cadet.dsl.speakeasy.net>
Raymond Toy <···@rtp.ericsson.se> writes:

> In the latest release of series, series fails to work on MCL because
> series use of LOCALLY.  In cmulisp and clisp, LOCALLY gets macroexpanded
> into a LET, so series never sees LOCALLY forms.
> Is there anything wrong with doing this?  That is, converting a
> (locally declares forms)
> into
> (let () declares forms)
> It seems ok to me, but I'm not sure.

I considered this at some point too, and remember a post at some point
in the past where LOCALLY was discussed (I think it happened when I
had suggested that someone change their binding-less LET into a
LOCALLY, and then someone else mentioned that ACL's LOCALLY was broken
or something like that.  Anyway, from that discussion, and from my
recollection, LOCALLY is pretty much the same as a binding-less LET
form.  If you are writing a macro (i.e.  DEFMACRO) and want to put
declarations around the macro definition, and still want your macro to
have top-levelness, I think you're safe using the LOCALLY special
form.  After all, it is not a macro that simply expands into a LET
form.  Basically, they're the same.  It's probably just nicer to use a
LOCALLY form instead of LET when there are no bindings and you're only
trying to get your decls in.

Check to see if LOCALLY is a macro or a special form in the
implementation you're using.  If it's a macro, that might be the
source of your problems.  My guess is that CMUCL still has LOCALLY as
a macro.

dave
From: Raymond Toy
Subject: Re: locally and let?
Date: 
Message-ID: <4n8zs71eg7.fsf@rtp.ericsson.se>
>>>>> "David" == David Bakhash <·····@alum.mit.edu> writes:

    David> I considered this at some point too, and remember a post at some point
    David> in the past where LOCALLY was discussed (I think it happened when I
    David> had suggested that someone change their binding-less LET into a
    David> LOCALLY, and then someone else mentioned that ACL's LOCALLY was broken
    David> or something like that.  Anyway, from that discussion, and from my

Thanks for the comments.  In any case, I think I've found the solution
for series that doesn't do this kind of hack.

    David> Check to see if LOCALLY is a macro or a special form in the
    David> implementation you're using.  If it's a macro, that might
    David> be the source of your problems.  My guess is that CMUCL
    David> still has LOCALLY as a macro.

Yep.  It seems that CLISP also has LOCALLY as a macro.

Ray
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m2zoknf6ps.fsf@cadet.dsl.speakeasy.net>
Raymond Toy <···@rtp.ericsson.se> writes:

> Thanks for the comments.  In any case, I think I've found the
> solution for series that doesn't do this kind of hack.

yeah.  I'm glad that it's getting there.  I'd personally much rather
see that CMUCL and CLISP get fixed up with respect to LOCALLY being a
special operator than seeing code that would otherwise use LOCALLY
instead use something else (i.e. binding-less LET).

I don't know if I mentioned it before, but it might be possible to fix 
up LOCALLY in CLISP and CMUCL without messing with the compiler
source.  I think that by using COMPILER-LET and/or
DEFINE-COMPILER-MACRO it might be possible to fix up the problem with
LOCALLY.  Not too sure though.

dave
From: Raymond Toy
Subject: Re: locally and let?
Date: 
Message-ID: <4nd7hjytoj.fsf@rtp.ericsson.se>
>>>>> "David" == David Bakhash <·····@alum.mit.edu> writes:

    David> yeah.  I'm glad that it's getting there.  I'd personally much rather
    David> see that CMUCL and CLISP get fixed up with respect to LOCALLY being a
    David> special operator than seeing code that would otherwise use LOCALLY
    David> instead use something else (i.e. binding-less LET).

I don't quite follow.  LOCALLY (whether a macro or special form) works
in CMUCL and CLISP, right?

    David> I don't know if I mentioned it before, but it might be possible to fix 
    David> up LOCALLY in CLISP and CMUCL without messing with the compiler
    David> source.  I think that by using COMPILER-LET and/or
    David> DEFINE-COMPILER-MACRO it might be possible to fix up the problem with
    David> LOCALLY.  Not too sure though.

What's the problem with LOCALLY here?  That it's a macro and not a
special form?  Even though it's a macro, it seems to work just fine
for CLISP and CMUCL.  Will your suggestion make LOCALLY a special
form?

Is there any code (except code walkers) that actually depends on
LOCALLY being a special form?

Can't speak for CLISP, but I've submitted a patch for CMUCL that makes
LOCALLY a special form (by modifying the compiler).  Whether it's
correct or not, I can't really say, but it seems to work for me after
a minute of testing. :-)

Ray
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m38zs7hyvr.fsf@cadet.dsl.speakeasy.net>
Raymond Toy <···@rtp.ericsson.se> writes:

> I don't quite follow.  LOCALLY (whether a macro or special form) works
> in CMUCL and CLISP, right?

For my purposes, yeah, it's the same if it just macroexpands into a
LET.  But that's me.  I don't usually need top-levelness in the way
that LOCALLY is supposed to preserve it.

> Is there any code (except code walkers) that actually depends on
> LOCALLY being a special form?

I think there is.  Check out:

http://www.xanalys.com/software_tools/reference/HyperSpec/Issues/iss219-writeup.html

I think they have a fine example of a difference.

dave
From: Tim Bradshaw
Subject: Re: locally and let?
Date: 
Message-ID: <ey3u2au6ckh.fsf@cley.com>
* Raymond Toy wrote:
> Is there any code (except code walkers) that actually depends on
> LOCALLY being a special form?

Yes.  Or rather, if it's a macro it must expand into something which
isn't otherwise defined by CL.  The issue I'm aware of is that LOCALLY
must preserve `top-levelness' in EVAL-WHEN forms:

Consider this fragment of code, occurring at top level in a file.

 (eval-when (:load-toplevel)
   (print 1)
   (locally
     (print 2)
     (eval-when (:compile-toplevel)
       (print 3)))
   (let ()
     (eval-when (:compile-toplevel)
       (print 4))))

A conforming implementation will print

 3

at compile time, and

 1
 2

at load time.  It will never print 4.

This is because (print 1) is at toplevel, inside a :load-toplevel
form.  (print 2) is *also* at toplevel, and inside the same form.
(print 3) is *also* at toplevel, but is now within a :compile-toplevel
form (note this *overrides* the :load-toplevel form: I think that's
extremely counterintuitive, but it seems to be what the standard
implies).  (print 4) is *not* at toplevel (because of LET) , but is
inside a :compile-toplevel form, and thus will never happen.

PROGN also has this characteristic of preserving top-levelness.
However there is nothing else that LOCALLY could expand into which
preserves top-levelness and allows declarations: therefore LOCALLY
must be special.

Relatively recently I was forced to find out all about this -- it
matters when you have things like macros which expand to :compile-toplevel
forms whose effect you wish to delay until load time -- and of the CLs
I tried: acl 5.0.1 is conforming, CLISP and CMUCL are not (Genera 8.3
is though!).

I'd be very glad if someone could point out that the overridingness of
EVAL-WHEN forms is not what the standard implies!

--tim
From: Rainer Joswig
Subject: Re: locally and let?
Date: 
Message-ID: <joswig-7F7BF8.11424703102000@news.is-europe.net>
In article <···············@cley.com>, Tim Bradshaw <···@cley.com> 
wrote:

> * Raymond Toy wrote:
> > Is there any code (except code walkers) that actually depends on
> > LOCALLY being a special form?
> 
> Yes.  Or rather, if it's a macro it must expand into something which
> isn't otherwise defined by CL.  The issue I'm aware of is that LOCALLY
> must preserve `top-levelness' in EVAL-WHEN forms:
> 
> Consider this fragment of code, occurring at top level in a file.
> 
>  (eval-when (:load-toplevel)
>    (print 1)
>    (locally
>      (print 2)
>      (eval-when (:compile-toplevel)
>        (print 3)))
>    (let ()
>      (eval-when (:compile-toplevel)
>        (print 4))))
> 
> A conforming implementation will print
> 
>  3
> 
> at compile time, and
> 
>  1
>  2
> 
> at load time.  It will never print 4.

MCL says:

? 
;Compiling "Camille:Lisp:MCL 4.3:test1.lisp"...
 Toplevel Forms...
 Toplevel Forms...
 Toplevel Forms...
 Toplevel Forms...
 Toplevel Forms...
 Toplevel Forms...  (Compiletime)

3 
 Toplevel Forms...
? 
;Loading #P"Camille:Lisp:MCL 4.3:test1.pfsl"...
1 
2

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Tim Bradshaw
Subject: Re: locally and let?
Date: 
Message-ID: <ey3hf6u5hb4.fsf@cley.com>
* Rainer Joswig wrote:
> MCL says:

<the right thing, I think>

For what it's worth I tested with CMUCL and CLISP (I changed the print
to go to *DEBUG-IO* but it didn't seem to matter)

CLISP: prints 3 4 at compile time
       prints 1 2 on loading fasl
       prints nothing on loading source

CMUCL: prints nothing on compile
       prints 2 1 (!) on loading fasl
       prints 2 1 on loading source

ACL: prints 3 on compile
     prints 1 2 on loading fasl
     prints nothing on load of source

Genera: prints nothing on compile
        prints 1 2 on loading fasl
        prints 1 2 on loading source

So I don't think any of these implementations gets it quite right,
though ACL is probably close enough -- it seems to get it completely
right except when loading source.

--tim
From: Raymond Toy
Subject: Re: locally and let?
Date: 
Message-ID: <4nvgvaxcx8.fsf@rtp.ericsson.se>
>>>>> "Tim" == Tim Bradshaw <···@cley.com> writes:

    Tim> * Rainer Joswig wrote:
    >> MCL says:

    Tim> <the right thing, I think>

Thanks for the example.  

    Tim> For what it's worth I tested with CMUCL and CLISP (I changed the print
    Tim> to go to *DEBUG-IO* but it didn't seem to matter)

    Tim> CMUCL: prints nothing on compile
    Tim>        prints 2 1 (!) on loading fasl
    Tim>        prints 2 1 on loading source

This is odd.  My version of CMUCL prints 1 2.

Ray
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m2d7hihrye.fsf@cadet.dsl.speakeasy.net>
Raymond Toy <···@rtp.ericsson.se> writes:

> >>>>> "Tim" == Tim Bradshaw <···@cley.com> writes:
> 
>     Tim> CMUCL: prints nothing on compile
>     Tim>        prints 2 1 (!) on loading fasl
>     Tim>        prints 2 1 on loading source
> 
> This is odd.  My version of CMUCL prints 1 2.

here's what mine does, and I've very recently installed CMUCL, though
admittedly I was lazy and installed the binary distribution.

It definitely didn't do the right thing at all times (see below):

[····@cadet /tmp]$ /usr/local/bin/cmucl
CMU Common Lisp 18c, running on cadet
Send questions and bug reports to your local CMU CL maintainer, or to ··········@cons.org. and ·········@cons.org. respectively.
Loaded subsystems:
    Python 1.0, target Intel x86
    CLOS based on PCL version:  September 16 92 PCL (f)
* (load "test")

; Loading #p"/tmp/test.lisp".

1 
2 
T
* (compile-file "test")

Python version 1.0, VM version Intel x86 on 03 OCT 00 11:14:21 am.
Compiling: /tmp/test.lisp 03 OCT 00 08:59:58 am

Byte Compiling Top-Level Form: 

test.x86f written.
Compilation finished in 0:00:00.

#p"/tmp/test.x86f"
NIL
NIL
* (load "test.x86f")

; Loading #p"/tmp/test.x86f".

1 
2 
T
* 
From: Duane Rettig
Subject: Re: locally and let?
Date: 
Message-ID: <4wvfpvfm4.fsf@beta.franz.com>
Tim Bradshaw <···@cley.com> writes:

> ACL: prints 3 on compile
>      prints 1 2 on loading fasl
>      prints nothing on load of source
 ...

> So I don't think any of these implementations gets it quite right,
> though ACL is probably close enough -- it seems to get it completely
> right except when loading source.

Allegro CL does get it right.  Why would you expect

(eval-when (:load-toplevel) ...) 

to do anything at execute time?

If you want results during source-loading time as well as loading
a compiled file, try specifying it this way:

(eval-when (:load-toplevel :execute) ...) 

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: Tim Bradshaw
Subject: Re: locally and let?
Date: 
Message-ID: <ey3og114ou8.fsf@cley.com>
* Duane Rettig wrote:
>> So I don't think any of these implementations gets it quite right,
>> though ACL is probably close enough -- it seems to get it completely
>> right except when loading source.

> Allegro CL does get it right.  Why would you expect

> (eval-when (:load-toplevel) ...) 

> to do anything at execute time?

I wouldn't.  But I'm thinking of what happens after saying LOAD of a
source file as being load time, shortly followed by execute time.  I'm
probably wrong about that though.

--tim
From: Duane Rettig
Subject: Re: locally and let?
Date: 
Message-ID: <4vgv9v9ux.fsf@beta.franz.com>
Tim Bradshaw <···@cley.com> writes:

> * Duane Rettig wrote:
> >> So I don't think any of these implementations gets it quite right,
> >> though ACL is probably close enough -- it seems to get it completely
> >> right except when loading source.
> 
> > Allegro CL does get it right.  Why would you expect
> 
> > (eval-when (:load-toplevel) ...) 
> 
> > to do anything at execute time?
> 
> I wouldn't.  But I'm thinking of what happens after saying LOAD of a
> source file as being load time, shortly followed by execute time.  I'm
> probably wrong about that though.

It is important to understand that the ":load-" prefix in
:load-toplevel does not encompass all uses of the LOAD function, but
instead describes only what compile-file arranges to do with the
eval-when's form at load-time if it is at toplevel.  The loading of a
source file does not necessarily go through compile-file, and if it
does not, the form falls under :execute semantics only.

See sections 3.2.3 (third paragraph), and 3.8.5 (second and third
paragraphs in the Description section).

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: Duane Rettig
Subject: Re: locally and let?
Date: 
Message-ID: <4u2atv9hh.fsf@beta.franz.com>
Duane Rettig <·····@franz.com> writes:

> See sections 3.2.3 (third paragraph), and 3.8.5 (second and third
> paragraphs in the Description section).

Sorry to be cryptic; these references are in your favorite version of
the Ansi CL spec...

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: Tim Bradshaw
Subject: Re: locally and let?
Date: 
Message-ID: <ey3k8bo524h.fsf@cley.com>
* Duane Rettig wrote:

> See sections 3.2.3 (third paragraph), and 3.8.5 (second and third
> paragraphs in the Description section).

In particular (from 3.8.5): 

   The use of the situations :compile-toplevel (or compile) and
   :load-toplevel (or load) controls whether and when evaluation
   occurs when eval-when appears as a top level form in code processed
   by compile-file.

I think makes it completely clear what is meant, so I was wrong.  I
guess I'd never run across about this because I never load source
files...  I need to make another change to my system so it can be
loaded as source I guess.

--tim
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m2lmw43gky.fsf@cadet.dsl.speakeasy.net>
Tim Bradshaw <···@cley.com> writes:

> * Duane Rettig wrote:
> 
> > See sections 3.2.3 (third paragraph), and 3.8.5 (second and third
> > paragraphs in the Description section).
> 
> In particular (from 3.8.5): 
> 
>    The use of the situations :compile-toplevel (or compile) and
>    :load-toplevel (or load) controls whether and when evaluation
>    occurs when eval-when appears as a top level form in code processed
>    by compile-file.
> 
> I think makes it completely clear what is meant, so I was wrong.  I
> guess I'd never run across about this because I never load source
> files...  I need to make another change to my system so it can be
> loaded as source I guess.

Yeah.  I ran across this deal kinda recently too.  I hand't realized
the subtlety with respect to compiled code vs. non-compiled-code.

Now, I fix that by putting the :execute wherever there's a
:load-toplevel, and that's all there really is to it.

Personally, I have never seen a situation where you'd want to do
something where I need to use :execute and :load-toplevel separately
at top-level, but I'm glad that the feature is there.

Still, I'm not a big fan of the semantics of EVAL-WHEN, and really
just a lot of the top-level stuff.  For example, I still don't
understand why MULTIPLE-VALUE-PROG1 must be a special operator but
prog1 doesn't.  Is there something about multiple values?

Then, back to EVAL-WHEN.  I would like to think I understand it, but
then, in the last example in the HS, it says, at:

http://www.xanalys.com/software_tools/reference/HyperSpec/Body/speope_eval-when.html#eval-when

;;;     If this form occurs at toplevel of a file to be compiled, FOO6 is
;;;     printed at compile time. [...]
 (eval-when (:execute :load-toplevel)
   (eval-when (:compile-toplevel)
     (print 'foo6)))

Now, how can this be?  The first eval-when discludes
:compile-toplevel, so shouldn't its body be ignored at compile-time?
What's the deal here?

dave
From: Tim Bradshaw
Subject: Re: locally and let?
Date: 
Message-ID: <ey3bsx04te9.fsf@cley.com>
* David Bakhash wrote:
> ;;;     If this form occurs at toplevel of a file to be compiled, FOO6 is
> ;;;     printed at compile time. [...]
>  (eval-when (:execute :load-toplevel)
>    (eval-when (:compile-toplevel)
>      (print 'foo6)))

> Now, how can this be?  The first eval-when discludes
> :compile-toplevel, so shouldn't its body be ignored at compile-time?
> What's the deal here?

The issue is that, when the compiler sees an EVAL-WHEN of
:LOAD-TOPLEVEL at top level, it continues to process the body *at top
level*.  All it does is not to *evaluate* them at compile time, but
arrange for them to be evaluated at load time. So when, within the
body, it sees an EVAL-WHEN of :COMPILE-TOPLEVEL directly within the
body, it then must evaluate *this* form's body at compile time.

This comes round full circle, because *this* is one of the reasons
that LOCALLY must be special: it must preserve toplevelness the same
way PROGN does, and there is no other way of doing this.

If it's not clear from the history of this thread, I find this whole
thing incredibly confusing too!

--tim
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m2ya041td2.fsf@cadet.dsl.speakeasy.net>
Tim Bradshaw <···@cley.com> writes:

> * David Bakhash wrote:
> > ;;;     If this form occurs at toplevel of a file to be compiled, FOO6 is
> > ;;;     printed at compile time. [...]
> >  (eval-when (:execute :load-toplevel)
> >    (eval-when (:compile-toplevel)
> >      (print 'foo6)))
> 
> > Now, how can this be?  The first eval-when discludes
> > :compile-toplevel, so shouldn't its body be ignored at
> > compile-time?  What's the deal here?
> 
> The issue is that, when the compiler sees an EVAL-WHEN of
> :LOAD-TOPLEVEL at top level, it continues to process the body *at
> top level*.  All it does is not to *evaluate* them at compile time,
> but arrange for them to be evaluated at load time.

Yes.  I feel better now.  thanks for the help.  I got lost between
evaluation and compilation there.

dave
From: David Bakhash
Subject: Re: locally and let?
Date: 
Message-ID: <m2hf6ujcow.fsf@cadet.dsl.speakeasy.net>
A test for LispWorks...(I put the stuff in a file called
"test.lisp").  It seems to work correctly as well:

CL-USER 2 > (load "test")

; Loading text file /tmp/test.lisp
#P"/tmp/test.lisp"

CL-USER 3 > (compile-file "test")

;;; Compiling file test ...
;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 0
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3, GC safety = 3
;;; Source level debugging is on 
;;; Source file recording is  on 
;;; Cross referencing is on
; (TOP-LEVEL-FORM 1)
; (TOP-LEVEL-FORM 2)
; (TOP-LEVEL-FORM 3)

3 
; (TOP-LEVEL-FORM 4)
; (TOP-LEVEL-FORM 5)
#P"/tmp/test.ufsl"
NIL
NIL

CL-USER 4 > (load "test.ufsl")

; Loading fasl file /tmp/test.ufsl

1 
2 
;  Loading fasl file /opt/local/lib/LispWorks/lib/4-1-0-0/modules/concat/xref.ufsl
#P"/tmp/test.ufsl"

CL-USER 5 > ;; dave