From: Neil Cohen
Subject: Misuse of Dynamic Variables
Date: 
Message-ID: <ncohen-1003011357290001@max2-96.ip.realtime.net>
In MCL 4.0, if the name of  special variable is used as a parameter in a
function which itself creates a function, the value of the special
variable is used.  For example: 

(defvar spades )
(setq spades 2)
(defun foo (spades)
  #'(lambda () (list  spades)))

 (funcall (foo 3))
 (setq spades 4)
  (funcall (foo 5))


produces:

SPADES
2
FOO
(2)
4
(4)

 What should happen?

  If the parameter is in a simple function, the value of the argument is used:

   (defun bar (spades)
  spades)
 (setq spades 3)
(bar 4)
(setq spades 5)
(bar 6)
             

     produces

 BAR
3
4
5
6

Neil Cohen
Bridge Trix
Producers of the Bobby Wolff Bridge Mentoring Series
 http://www.bridgetrix.com

From: Kent M Pitman
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <sfwvgphjm1b.fsf@world.std.com>
······@bridgenospamtrix.com (Neil Cohen) writes:

> In MCL 4.0, if the name of  special variable is used as a parameter in a
> function which itself creates a function, the value of the special
> variable is used. [...]

Sounds like something to report the vendor.
From: Rob Warnock
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <98eo34$2qkvc$1@fido.engr.sgi.com>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| ······@bridgenospamtrix.com (Neil Cohen) writes:
| > In MCL 4.0, if the name of  special variable is used as a parameter in a
| > function which itself creates a function, the value of the special
| > variable is used. [...]
| 
| Sounds like something to report the vendor.
+---------------

I missed this one too on first reading (though I'm mildly surprised
Kent didn't see it -- perhaps skimmed over it a little too quickly?).  ;-}
I had to run the example through CLISP and CMUCL (which give the same
results as MCL) and stare at it a bit before I noticed that "obviously"
the code is doing exactly the *RIGHT* thing!!  [Ref to old math joke...]

Neil's confusion is about when the value of the special is being used,
which is *not* when the closure is created, but when it's *called*. Let's
rewrite the example, using the *...* convention on the special (to avoid
picking up bad habits), and adding an auxiliary variable to capture the
value of the special at the time when the closure is created:

	> (defvar *spades* 2)
	*SPADES*
	> (defun foo (*spades*)
	    (let ((lexical-spades *spades*))
	      #'(lambda () (list  *spades* lexical-spades))))
	FOO
	> (funcall (foo 3))
	(2 3)
	> (setq *spades* 4)
	4
	> (funcall (foo 5))
	(4 5)
	> 

So by the time the FUNCALL actually calls the closure, FOO has
already returned and thus the special *SPADES* has already been
restored (correctly!) to its global value.  Capische?


-Rob

-----
Rob Warnock, 31-2-510		····@sgi.com
SGI Network Engineering		<URL:http://reality.sgi.com/rpw3/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA
From: Barry Margolin
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <LKCq6.3$wM6.10891@burlma1-snr2>
In article <···················@user-2ivea4h.dialup.mindspring.com>,
Daitaro Hagihara <··@mail.pls> wrote:
>In article <··············@fido.engr.sgi.com>, ····@rigden.engr.sgi.com 
>(Rob Warnock) wrote:
>
>> Neil's confusion is about when the value of the special is being used,
>> which is *not* when the closure is created, but when it's *called*.
>
>But still, defun-first, defvar-second approach gives the answer he wanted.

That's to be expected.  At the time the DEFUN is compiled or executed, it's
not yet a special variable, so a lexical closure is created.

>This is excessively confusing.  I've met with similar confusing issue
>involving macros recently, for which I haven't found a clue yet.

Forms are processed in order, so declarations and macro definitions only
affect the forms that follow them.  What's so confusing?

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, 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: Pierre R. Mai
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <871ys4zcbc.fsf@orion.bln.pmsf.de>
··@mail.pls (Daitaro Hagihara) writes:

> In article <·················@burlma1-snr2>, Barry Margolin 
> <······@genuity.net> wrote:
> 
> > Forms are processed in order, so declarations and macro definitions only
> > affect the forms that follow them.  What's so confusing?
> 
> Well, for one thing, stream redirection can'y be done for macros,
> because I suppose dynamic scope of redefined stdout has ended by
> the time macros get expanded and run, which is similar to what
> happened here.  If these behaviors are not confusing, then what
> are they called (or characterised)?  Just curious to know...

Would you post an example of what you attempted, and a short
description of what you wanted to achieve, and why you believe your
approach should work/doesn't work?  It seems to me that there is some
underlying confusion to your confusion, since stream redirection isn't
in any way special.  It would probably be best to get to the bottom of
this sooner, rather than later, or you'll probably fall prey to other
confusion as well.

Most people get confused around macros, because they fail to keep
track of the different times of evaluation that occur in Lisp.  That
is only confusing to the newcomer, but is to be expected, because most
other languages only have one or two user-accessible evaluation
"times", so they are being exposed to something completely new, and
are not equipped to deal with the resulting complexity.  Once you have
wrapped your head around the basic facts, instead of trying to
extrapolate from prior experiences, there is no source of confusion
left, and you'll be wondering what got you so confused in the first
place.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Pierre R. Mai
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <87ae6sxdoh.fsf@orion.bln.pmsf.de>
··@mail.pls (Daitaro Hagihara) writes:

> Thanks guys.  But I fail to understand people "understanding" this
> obvious inconsistency in Lisp.  Anyway, my short example is this:

Well, as we shall see, there is no inconsistency in Lisp, your
expectations are inconsistent with reality.

> (defvar win (ed))

I assume you are aware of the convention of using '*' around special
variables (like the ones produced by defvar, defparameter, etc.).

> (defmacro foo ()
>   (print 1))

What is the purpose of such a macro?  Do you really want to print 1
each time the macro is _expanded_?  Do you really want to have 1 (the
value returned by (print 1)) to be the expansion of the macro?  Other
than for observing the expansion behaviour of your implementation, I
fail to see any uses of a macro of this sort, so I assume you want to
achieve something else entirely, and are, in your confusion about the
mechanisms of macros and macro-expansion, going about it in the wrong
way.  Maybe if you could show us some real code, _and_ a description of
what you really wanted to achieve, so that we can show you the correct
ways of achieving your goals?

> Now, (foo) works as expected.  But

For very strange values of "expected", I'd say.  What would your
expectations tell you about the following form:

(dotimes (i 10) (foo))

How many 1's do you expect will get printed?  I bet you expect 10 1's
to be printed, right?  Well, this _could_ happen, if you interact with
a "naive" interpreter (like the one in CLISP).  But if you interact
with a more "intelligent" interpreter, and/or a compiler, most likely
you'll only get one 1 printed, since foo is only expanded once, and
then the expansion is interpreted/executed, instead of constantly
re-expanding the macro form.

> (let ((*standard-output* win))
>   (foo))

> doesn't work as I expect it to.

Why? What did you expect?

(let ((*standard-output* win))
  (foo))

will be expanded to

(let ((*standard-output* win))
  1)

In the course of this expansion, your (print 1) will be executed
(maybe multiple times, since there is no guarantee as to when exactly
macros are expanded, how often they are expanded, etc.), but since
this can happen before *standard-output* is rebound (which will happen
at execution-time of the form, which usually is after macro-expansion
time, though it might be interleaved with macro-expansion in a "naive"
interpreter), it will obviously not go to win.

Indeed CLISP's interpreter will produce the following output:

[3]> (defvar *demo-output* (make-string-output-stream))
*DEMO-OUTPUT*
[4]> (get-output-stream-string *demo-output* )
""
[5]> (let ((*standard-output* *demo-output*)) (dotimes (i 10) (foo)))

1 
1 
NIL
[6]> (get-output-stream-string *demo-output* )
"
1 
1 
1 
1 
1 
1 
1 
1 
1 
1 
1 
1 "

So (foo) gets macro-expanded twice before(/after) *standard-output* is
bound (probably to check for declarations, etc.), and then it is
expanded another 12 times while *standard-output* is rebound.  All of
this is because CLISP's interpreter interleaves macro-expansion and
execution, as it is allowed to do by the standard.

If we now use CLISP's compiler, we'll see different behaviour:

[12]> (get-output-stream-string *demo-output* )
""
[13]> (compile nil '(lambda () (let ((*standard-output* *demo-output*)) (dotimes (i 10) (foo)))))

1 
1 
1 
1 
1 
#<COMPILED-CLOSURE NIL> ;
NIL ;
NIL
[14]> (funcall *)
NIL
[15]> (get-output-stream-string *demo-output* )
""

So now foo is expanded 5 times during compilation, and of course never
during execution, so at no time will 1's be printed to *demo-output*.

All of this variance in behavior is perfectly Ok, BTW, since macros
(or more specifically their expansion functions) are supposed to be
source code transformations, and as such to be real functions,
i.e. time-invariant and non-side-effecting, so that differences in
calling patterns are never observable.  If your macros _do_ include
side-effect (like foo), then you are expected to ensure that they will
remain time-invariant, and consistent, regardless of the exact calling
pattern.

In any case, I'd expect that you really wanted define the following
macro:

(defmacro foo ()
  `(print 1))

This is much more likely to do what you both intended, and expected,
and it will interact as you expect with your rebinding of
*standard-output*:

(let ((*standard-output* win))
  (foo))

will now be expanded to

(let ((*standard-output* win))
  (print i))

which will print 1 to win, since that is the current value of
*standard-output* at execution time, and it will return 1.

Furthermore, since your expansion function now is both
time-independent, and non-side-effecting, you'll be unable to observe
any differences in macro-expansion behaviour of different
implementations (and hence don't have to worry about it).

I'd suggest you read up about macros and macro-programming in a good
book on Lisp, like e.g. On Lisp by Paul Graham.  Or take a look at the
relevant sections of Successful Lisp by David B. Lamkins (which is
available online at http://psg.com/~dlamkins/sl/sl.html ).

> Back to the original example.  According to CLtL2 p.43ff, function
> args are bound to what were passed to the function.  There is no
> mention of exception whatsoever to this simple (and predictable)
> behavior.  So, while it is understandable to know why Lisp behaved

And there _is_ no exception to this rule.  Let us reconsider the code
in question.

(defvar spades)
(setq spades 2)

(defun foo (spades)
  #'(lambda () (list  spades)))

(funcall (foo 3))

(setq spades 4)
(funcall (foo 5))

In every call to foo, spades _is_ bound to the argument passed.  We
will see this, if we use a slightly different definition of foo:

(defun foo (spades)
  (format *trace-output* "Current value of spades: ~S~%" spades)
  #'(lambda () (list spades)))

Now let us look at what happens:

* (defvar spades)

SPADES
* (setq spades 2)

2
* (defun foo (spades)
    (format *trace-output* "Current value of spades: ~S~%" spades)
  #'(lambda () (list spades)))

FOO
* (foo 3)    
Current value of spades: 3
#<Interpreted Function (LAMBDA () (LIST SPADES)) {480DE3B9}>
* (funcall *)

(2)
* (setq spades 4)

4
* (foo 5) 
Current value of spades: 5
#<Interpreted Function (LAMBDA () (LIST SPADES)) {480DE3B9}>
* (funcall *)

(4)

So the value of spades accessible within foo is the value passed in,
just as expected.  No surprises or inconsistencies there.

So why does _the function returned by foo_ not access that binding,
like it would if spades was a lexical variable, instead of a special
variable?  Because the closure produced by the function form closes
over the _lexical environment_ only, it doesn't close over the
special/dynamic environment (see Section 3.1.4 Closures and Lexical
Binding, of the ANSI standard/the HyperSpec) present at the time.

So the reference to spades within the lambda-form is a free reference,
and it will access the binding of spades _current at the time the
function is executed_, not the one current at definition time (as it
would if the special environment was closed over).  In the absence of
any intervening bindings, this will be the global value of spades, as
can be seen in this example:

* (setq spades 10)

10
* (foo 20)
Current value of spades: 20
#<Interpreted Function (LAMBDA () (LIST SPADES)) {480DE3B9}>
* (defvar myfun *)

MYFUN
* (funcall myfun)

(10)
* (setq spades 12)

12
* (funcall myfun)

(12)
* (let ((spades 30)) (funcall myfun))

(30)

The fact that the reference to spades in the lambda-form really
is completely free, not closed over, and hence resolved at run-time
can be made even more drastically apparent, if we remove the global
binding of spades (run the following in a new image, or evaluate
(makunbound 'spades) first): 

* (defun foo (spades)
    (declare (special spades))
    (format *trace-output* "Current value of spades: ~S~%" spades) 
    #'(lambda () (list spades)))

FOO
* (foo 10)
Current value of spades: 10
#<Interpreted Function (LAMBDA () (LIST SPADES)) {480DDB29}>
* (funcall *)

Error in KERNEL::UNBOUND-SYMBOL-ERROR-HANDLER:  the variable SPADES is unbound.

Restarts:
  0: [ABORT] Return to Top-Level.

Debug  (type H for help)

(EVAL::LEAF-VALUE
 #<C::REF #x480DA8AD
     LEAF= #<C::GLOBAL-VAR #x480D9AAD
               NAME= SPADES
               WHERE-FROM= :DECLARED
               KIND= :SPECIAL>>
 0
 #())
Source: 
; File: target:compiler/eval.lisp
(SYMBOL-VALUE (C::GLOBAL-VAR-NAME LEAF))
0] 

> as it did in the original example, I still consider that this is
> an ambiguous behavior of Lisp if not so blatantly inconsistent.

Neither is the behaviour ambiguous (there's no room for interpretation
here), nor inconsistent (inconsistent with what, one would have to
ask, in any case).

> If I'm wrong, then I'd appreciate any help.

I hope you can see clearly now the rain has gone... ;)

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Kent M Pitman
Subject: Re: Misuse of Dynamic Variables
Date: 
Message-ID: <sfwvgpgn7cv.fsf@world.std.com>
····@rigden.engr.sgi.com (Rob Warnock) writes:

> Kent M Pitman  <······@world.std.com> wrote:
> +---------------
> | ······@bridgenospamtrix.com (Neil Cohen) writes:
> | > In MCL 4.0, if the name of  special variable is used as a parameter in a
> | > function which itself creates a function, the value of the special
> | > variable is used. [...]
> | 
> | Sounds like something to report the vendor.
> +---------------
> 
> I missed this one too on first reading (though I'm mildly surprised
> Kent didn't see it -- perhaps skimmed over it a little too quickly?).  ;-}

Nah, I was just trying to trick you into writing the explanation of
what's really going on so I wouldn't have to.  Calculated play on my
part.  OBVIOUSLY I would never be tricked by something like this.
Really.. I'm infallible, you know.  Honest.  Things like this NEVER
get by me...



                                                             oops.  :-)