From: David Sletten
Subject: Dynamic variable question
Date: 
Message-ID: <3CD7CB69.2030408@slytobias.com>
I just fell out of my chair. I discovered a huge hole in a topic I 
thought I understood...

I ran across something like this:
(with-open-file (out "pung.dat" :direction :output)
   (let ((*standard-output* out))
     (format t "foo") . . .))

At first I couldn't figure out how it worked since I thought the LET 
form created a lexical variable that FORMAT wouldn't be able to see.

After some research and experimentation I now realize that since 
*STANDARD-OUTPUT* is a special variable at top level it retains this 
status inside the LET form. LET does not create a lexical variable here. 
Then FORMAT has access to this temporary binding and the redirection of 
output works.

In my understanding of lexical/dynamic scope I recognized this distinction:
(defun foo (x)
   (pung))

(defun pung ()
   (1+ x))

(foo 2) => ERROR

Whereas:
(defun foo (x)
   (declare (special x))
   (pung))

(foo 2) => 3

What I didn't realize is that the following causes the same result as 
the 2nd case above:
(defvar x 9)

(defun foo (x)
   (pung))

(foo 2) => 3

The function FOO doesn't need to declare its parameter special since 
DEFVAR creates a special variable X. (CLHS illustrates a similar example 
on the DEFVAR/DEFPARAMETER page.)

I've always seen lexical scope described such that a variable is only 
visible within the text of the form in which it's defined (e.g., LET, 
DEFUN). This implies that the scope of a variable should be clear simply 
by looking at the code. If I understand things correctly (now!) this is 
wrong. The existence of a dynamic variable in the environment in which a 
function is defined can affect the scope of said function's parameters 
and local variables.

Do I have things worked out now? If so it seems kind of dangerous that 
you can't tell the scope of a function's parameters in isolation. I 
guess this is one reason to follow the *var* convention Kent recently 
mentioned. X would be a parameter, while *X* would be the top level 
special variable.

I appreciate any clarification of these issues.

Thanks,
David Sletten

From: Barry Margolin
Subject: Re: Dynamic variable question
Date: 
Message-ID: <zlRB8.5$B23.324@paloalto-snr1.gtei.net>
In article <················@slytobias.com>,
David Sletten  <·····@slytobias.com> wrote:
>Do I have things worked out now? If so it seems kind of dangerous that 
>you can't tell the scope of a function's parameters in isolation.

That's why they're called "special" -- they violate the rule of referential
transparency.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Erik Naggum
Subject: Re: Dynamic variable question
Date: 
Message-ID: <3229770069494580@naggum.net>
* David Sletten
| At first I couldn't figure out how it worked since I thought the LET form
| created a lexical variable that FORMAT wouldn't be able to see.

  There is a difference between a global (pervasive) and a local special
  declaration that you may have missed.  The former is obtained with
  declaim, the latter with declare.  defvar does the declaim part.

| In my understanding of lexical/dynamic scope I recognized this
| distinction:

| (defun foo (x)
|    (pung))
| 
| (defun pung ()
|    (1+ x))
| 
| (foo 2) => ERROR
| 
| Whereas:
| (defun foo (x)
|    (declare (special x))
|    (pung))
| 
| (foo 2) => 3

  You should _really_ (declare (special x)) in pung, too.

| I've always seen lexical scope described such that a variable is only
| visible within the text of the form in which it's defined (e.g., LET,
| DEFUN).  This implies that the scope of a variable should be clear simply
| by looking at the code.  If I understand things correctly (now!) this is
| wrong.  The existence of a dynamic variable in the environment in which a
| function is defined can affect the scope of said function's parameters
| and local variables.

  What does it is the special proclamation/declamation, not the variable.
  The two are strictly speaking separate concepts.  You may pervasively
  declare any symbol to have special binding independent of its top-level
  binding.  In other words, (defvar x) only makes it special, but it is
  still unbound.  You may actually use a symbol for its variable property
  without making it special.

| Do I have things worked out now?

  Well, no, the underlying mechanism is simpler than you think it is.

| If so it seems kind of dangerous that you can't tell the scope of a
| function's parameters in isolation.

  Well, there are dangers in life.  Your task is to cope with them.  There
  are also declared constants.

| I guess this is one reason to follow the *var* convention Kent recently
| mentioned.  X would be a parameter, while *X* would be the top level
| special variable.

  Generally speaking, it is wise to use the *var* convention for all
  special bindings, not just global, special variables.
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.

  70 percent of American adults do not understand the scientific process.
From: David Sletten
Subject: Re: Dynamic variable question
Date: 
Message-ID: <3CD8D069.40800@slytobias.com>
Erik Naggum wrote:


>   There is a difference between a global (pervasive) and a local special
>   declaration that you may have missed.  The former is obtained with
>   declaim, the latter with declare.  defvar does the declaim part.
ables.

.
.
.

> 
>   What does it is the special proclamation/declamation, not the variable.
>   The two are strictly speaking separate concepts.  You may pervasively
>   declare any symbol to have special binding independent of its top-level
>   binding.  In other words, (defvar x) only makes it special, but it is
>   still unbound.  You may actually use a symbol for its variable property
>   without making it special.
> 

Thanks for the feedback, Erik. You've pointed out a number of things I 
need to study more closely.

David Sletten
From: Paul Foley
Subject: Re: Dynamic variable question
Date: 
Message-ID: <m2elgntd9w.fsf@mycroft.actrix.gen.nz>
On Tue, 07 May 2002 12:40:35 GMT, David Sletten wrote:

> I just fell out of my chair. I discovered a huge hole in a topic I 
> thought I understood...

> I ran across something like this:
> (with-open-file (out "pung.dat" :direction :output)
>    (let ((*standard-output* out))
>      (format t "foo") . . .))

FWIW, you can write just

  (with-open-file (*standard-output* "pung.dat" :direction :output)
    ...)

The extra LET serves no purpose.

-- 
If that makes any sense to you, you have a big problem.
                                      -- C. Durance, Computer Science 234
(setq reply-to
  (concatenate 'string "Paul Foley " "<mycroft" '(··@) "actrix.gen.nz>"))
From: David Sletten
Subject: Re: Dynamic variable question
Date: 
Message-ID: <3CD8D117.2020305@slytobias.com>
Paul Foley wrote:

>>I ran across something like this:
>>(with-open-file (out "pung.dat" :direction :output)
>>   (let ((*standard-output* out))
>>     (format t "foo") . . .))
>>
> 
> FWIW, you can write just
> 
>   (with-open-file (*standard-output* "pung.dat" :direction :output)
>     ...)
> 
> The extra LET serves no purpose.
> 
> 

In general I completely agree with you. However, I can imagine a 
(perhaps unusual) situation where you might want to 'release' the 
binding of *STANDARD-OUTPUT* yet still maintain the stream OUT for 
further output. That would be the only reason to do it the way I 
illustrated.

Thanks for pointing this out.

David Sletten