More Scope...

12 views
Skip to first unread message

Robert Munyer

unread,
Feb 22, 2000, 3:00:00 AM2/22/00
to
In article <33Dr4.39317$632.1...@news1.rdc2.on.home.com>,
Tyler Durden <maxq...@hotmail.com> wrote:

> So, would
> (defun fact (x) (cond ((<= x 0) 1) ('t (* x (fact (1- x))))))
> (setq x 7)
> (fact 3)
> return a stack overflow because of repeated calls to (fact 6)?

No, that version of FACT will work in a lexically scoped Lisp or
a dynamically scoped one. The code inside the function will use
the appropriate inner binding of X, not the outer binding X = 7.


> > > (defun foo (x) (eval x))
> > > (setq x 3)
> > > (foo '(+ x 2))

FOO is different, because it uses EVAL. In Common Lisp, FOO's
binding of X is lexical by default, and can't be accessed by the
code that's evaluated by EVAL. That's why, as [previous author]
said, 5 is correct in Common Lisp.

You can also get Common Lisp to do dynamic binding, just like those
older lisps, by declaring a variable to be "special." Note: it's
been reported that at least one CL implementation will implicitly
declare all uses of X to be special, including the ones in FOO,
when it sees your (SETQ X 3) at the top level. Doing it that way
is a "bad idea," and I hope the situation has been corrected by
now. If that implementation used a compiler, I suspect that it
would correctly return 5 the first time you tried your code above,
but then if you ever re-evaluated the DEFUN form again after
evaluating the SETQ, from then on the compiler would compile FOO
incorrectly, and then (FOO '(+ X 2)) would result in an error.

-- Robert Munyer <mun...@mcs.com>

P. S. A couple of years ago I had an exasperating flame war with
Erik over a question very similar to this one. I eventually won
the war, by finding an excerpt from the HyperSpec that demonstrated
the exact opposite of Erik's main technical argument.

But it was a Pyrrhic victory. Trying to have a technical debate
with Erik was so incredibly time-consuming and unproductive, and
so unpleasant in general, that as soon as I finished winning the
debate, I stopped reading this newsgroup for more than a year.

My advice to anyone who finds himself in a dispute with Erik: resist
the temptation to flame back. Do not try to respond (not even in
self defense) to the non-technical personal attacks. If you must
respond, limit your response to a statement like "That's an
inappropriate personal attack, and I won't dignify it with a
response." If you allow your debate to turn into a war of personal
attacks, it will waste a lot of bandwidth -- and I guarantee that
you won't enjoy the debate, even if you win it. (Unless you're
deliberately trolling for conflict, like the schizophrenic Perl
programmer who's been posting here lately!)

Erik Naggum

unread,
Feb 22, 2000, 3:00:00 AM2/22/00
to
* Robert Munyer <mun...@mcs.com>
| P.S. A couple of years ago I had an exasperating flame war with Erik

| over a question very similar to this one. I eventually won the war, by
| finding an excerpt from the HyperSpec that demonstrated the exact
| opposite of Erik's main technical argument.

August 1996. I think comp.lang.lisp readers deserve the opportunity to
read the discussion for themselves, not the least to understand why
Robert's self-serving summary is _still_ his position, and why it is
still important that he be shot down, because he's _still_ wrong, nearly
four years later.

the following "power search" line lists them from www.deja.com:

~g comp.lang.lisp ~dc {1996/08/01 1996/09/30} ~s {EVAL implementations}

the original question was why (let ((x 10)) (eval 'x)) produces different
results before and after a special declaration of x. this stumps newbies
at times, but it can be explained easily and well unless you get it wrong.

so the problem with that debate was that Robert insisted on bringing up a
*huge* number of *tiny* arguments. Robert _did_ field a war over quibbly
little details, while everybody else were either trying to unconfuse him,
calm him down, or putting in their earplugs. naturally, winning this war
meant nobody made the effort to respond to more of the same old rants.

my _main_ argument was that Common Lisp doesn't have a concept of "global
variables", but lexical and dynamic _bindings_, and lexical and global
symbol _references_ (explained in various bits and pieces -- the whole
discussion helped clarify the issues for me). Robert's main point was
that you could have a lexical and a dynamic variable with the same name.
he's right (and I _never_ disagreed with him on it, because it is wholly
irrelevant): the latter is called the symbol-value of a symbol that has
_not_ been declared special, because a reference to a variable that is
not lexical is identical to symbol-value of the symbol naming it. as
most confused people who are right, Robert was right for wrong reasons:
he didn't understand the distinction between binding and references to
variables. apparently, he learned nothing from the whole exercise.

here's an excerpt I think highlights exactly why Robert is _still_ upset:

> (part of) Robert's answer was wrong, relied on implementation specifics
> at best, and is no better off after his attempted rescue missions. end
> of story.

Wait a minute. STOP DOING THAT! It is rude and offensive. You keep
saying that part of my answer was wrong somehow, without specifying how.
Every time I challenge you to be specific you just post another article
saying (or implying) that I made some vague, unspecified error. That is
not a reasonable way to debate. In Usenet you are not supposed to simply
state that someone is wrong; you are supposed to explain WHY he or she is
wrong so that everyone can benefit.

I clearly fell short of his expectations. of course that's _my_ fault.

incidentally, Robert's parting words to us were as follows:

The standard example code above makes it absolutely clear that SETQ does
not, and must not, proclaim a symbol to be special.

no wonder it didn't really feel good to part on this winning note: it's
not a winning note. it's an admission of not remembering from early
warnings in the same discussion that examples are not even considered
part of the standard, for the very simple reason that the requirements
have to be _uniquely_ authoritative.

so the "excerpt from the HyperSpec that demonstrates the exact opposite
of Erik's main technical point" is simply a lie -- but it's the kind you
win wars with, because people normally let you think you won when you say
something sufficiently stupid and gloat and brag about it to boot.

#:Erik

Andrew Cooke

unread,
Feb 23, 2000, 3:00:00 AM2/23/00
to

I have a proposal to put to the group. We organise a fund to fly me to
wherever these two hang out, armed with my trusty ruler.

Once I return here I can email the group with the information about
exactly who has the larger penis and so settle the dispute beyond all
doubt.

Andrew

In article <31602521...@naggum.no>,


Erik Naggum <er...@naggum.no> wrote:
> * Robert Munyer <mun...@mcs.com>
> | P.S. A couple of years ago I had an exasperating flame war with
Erik
> | over a question very similar to this one. I eventually won the war,
by
> | finding an excerpt from the HyperSpec that demonstrated the exact
> | opposite of Erik's main technical argument.
>
> August 1996. I think comp.lang.lisp readers deserve the opportunity
to
> read the discussion for themselves, not the least to understand why
> Robert's self-serving summary is _still_ his position, and why it is
> still important that he be shot down, because he's _still_ wrong,
nearly
> four years later.

[...]


Sent via Deja.com http://www.deja.com/
Before you buy.

Erik Naggum

unread,
Feb 23, 2000, 3:00:00 AM2/23/00
to
* Andrew Cooke <and...@andrewcooke.free-online.co.uk>

| I have a proposal to put to the group.

me, too: if you have a problem with personal attacks, then stop doing it
_first_. continue _only_ if you actually _condone_ personal attacks.

#:Erik

Keke Abe

unread,
Feb 24, 2000, 3:00:00 AM2/24/00
to
In article <31602521...@naggum.no>, Erik Naggum wrote:

> my _main_ argument was that Common Lisp doesn't have a concept of "global
> variables", but lexical and dynamic _bindings_, and lexical and global
> symbol _references_ (explained in various bits and pieces -- the whole
> discussion helped clarify the issues for me). Robert's main point was
> that you could have a lexical and a dynamic variable with the same name.
> he's right (and I _never_ disagreed with him on it, because it is wholly
> irrelevant): the latter is called the symbol-value of a symbol that has
> _not_ been declared special, because a reference to a variable that is
> not lexical is identical to symbol-value of the symbol naming it. as
> most confused people who are right, Robert was right for wrong reasons:
> he didn't understand the distinction between binding and references to
> variables.

Could you explain the distinction? I've read the 1996 thread but could
not figure that out.


regards,
abe

Erik Naggum

unread,
Feb 25, 2000, 3:00:00 AM2/25/00
to
* Keke Abe

| Could you explain the distinction? I've read the 1996 thread but could
| not figure that out.

a binding of a lexical variable is an entirely new variable, one that may
be captured independently of any other variable, and which is not visible
anywhere else. a binding of a special variable is a dynamic association
between variable and value which is seen everywhere else the same
variable is referenced. the reference to a lexical variable is under the
supreme control of the compiler, which may allocate it to a register or
to a stack frame, and which will typically discard the symbol association.
the reference to a special variable is like a call to symbol-value on
that symbol.

this means that the statement "there may be a lexical and dynamic
variable with the same name" is terribly confused. yes, it is possible
to "forget" to declare a symbol special, which means any binding will be
lexical, but so, then, will any normal reference. in order to access the
symbol, you can no longer just name it, you need to call symbol-value or
set when you want to read or change its value. but at this time, we're
clearly doing something very different than what we did with variables --
we're actually tinkering with the underlying implementation of special
variables.

a fully true statement would be that the symbol-value slot of a symbol is
accessible and may be accessed also when the symbol has not been declared
special. however, using a variable means _not_ having to do anything
special like that at every access, so it's clear that we access a
symbol's internal information in code like this:

(1) common-lisp-user
;; In Lisp Listener #2
(2) common-lisp-user
(defun foobar (x)
(values x (symbol-value 'x)))
=> foobar
(3) common-lisp-user
(setq x 666)
=> 666
(4) common-lisp-user
(foobar 4711)
=> 4711
=> 666
(5) common-lisp-user
(defvar x 69)
=> x
(6) common-lisp-user
(foobar 4711)
=> 4711
=> 4711
(7) common-lisp-user

hope this helps.

#:Erik

Erann Gat

unread,
Feb 25, 2000, 3:00:00 AM2/25/00
to
In article <31604820...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:


> (1) common-lisp-user
> ;; In Lisp Listener #2
> (2) common-lisp-user
> (defun foobar (x)
> (values x (symbol-value 'x)))
> => foobar
> (3) common-lisp-user
> (setq x 666)
> => 666
> (4) common-lisp-user
> (foobar 4711)
> => 4711
> => 666
> (5) common-lisp-user
> (defvar x 69)
> => x
> (6) common-lisp-user
> (foobar 4711)
> => 4711
> => 4711

It takes a pretty smart implementation of Common Lisp to actually
produce this result as presented. In most systems you'll have to
recompile FOOBAR after DEFVARing X to see the result:

? (defun foo (x) (values x (symbol-value 'x)))
FOO
? (setf x 666)
666
? (foo 4711)
4711
666
? (defvar x 69)
X
? (foo 4711)
4711
69
? (defun foo (x) (values x (symbol-value 'x)))
FOO
? (foo 4711)
4711
4711
?

This was MCL 4.3.

Erann Gat
g...@jpl.nasa.gov

Jeff Dalton

unread,
Feb 25, 2000, 3:00:00 AM2/25/00
to
g...@jpl.nasa.gov (Erann Gat) writes:

> It takes a pretty smart implementation of Common Lisp to actually
> produce this result as presented.

Not really. GCL produces the result just as Erik gave it.

> In most systems you'll have to
> recompile FOOBAR after DEFVARing X to see the result:

I suspect that most systems still use an interpreter for the
read-eval-print loop, and most of them will work as Erik suggested.

Other issues:

1. I don't think there's anything especially confused about saying there
can be a lexical and a dymamic variable of the same name. That there
can be is why

(values x
(locally (declare (special x))
x))

can return two different values.

2. It's sometimes necessary to distinguish between declaring special
(with DECLARE) and proclaiming special (with PROCLAIM or DECLAIM).
DEFVAR proclaims the var special, and that makes it pervasively
"special everywhere" - but merely declaring something special has
only a local effect.

A further complication is the treatment of plain refs to "global"
variables. They are refs to the special variable. That is, a free x,
not declared or proclaimed special, and

(locally (declare (special x))
x)

refer to the same thing. [It's similar for assignment.]

3. CMUCL proclaims such "undeclared" free variables special
automatically. So far as I know, no other implementation does that.
They treat it as a ref to the special var and issue a warning, and
usually don't bother to warn when interpreting rather than compiling.

So far as I can recall, having looked into this one of the times when
it was an issue before, the ANSI standard does not explicitly forbid
CMUCL's behaviour.

(CLtL was reasonably clear that such refs were refs to the special
variable. The standard may not be so clear, and that may be what
allows CMUCL's behaviour. I don't remember what the standard says
well enough to say without spending a fair amount of time on it.)

In any case, I think CMUCL's behaviour should be forbidden, because
the consequences of proclaiming a variable special are so extreme.
Just because I type (setq x 100) to the top-level REPL doesn't mean
I want x to be special wherever it's used. Sure, if I'd typed
(setq *x* 100), having "forgotten" to defvar it, I might be happy
if *x* were proclaimed special automatically. But that isn't what
I typed.

These issues become clearer if you look at them from the point of view
of someone who never wants to proclaim anything special. It becomes
awkward to use "global" variables in that case, because compilers
issue warnings, and CMUCL proclaims them special by default.

There was a cleanup issue, PROCLAIM-LEXICAL, that would have dealt
with some of these issues, but it had consequences (such as lexical
globals) that made enough people reluctant to adopt it.

-- jd

Erann Gat

unread,
Feb 25, 2000, 3:00:00 AM2/25/00
to
In article <x266vdf...@todday.aiai.ed.ac.uk>, Jeff Dalton
<je...@todday.aiai.ed.ac.uk> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
>
> > It takes a pretty smart implementation of Common Lisp to actually
> > produce this result as presented.
>
> Not really. GCL produces the result just as Erik gave it.
>
> > In most systems you'll have to
> > recompile FOOBAR after DEFVARing X to see the result:
>
> I suspect that most systems still use an interpreter for the
> read-eval-print loop, and most of them will work as Erik suggested.

Quite so. I've been using MCL for so long, where (EVAL X) == (FUNCALL
(COMPILE (LAMBDA () X))) that I actually forgot about interpreted code.
(You can imagine how exasperated I must get when people complain that
Lisp is slow because it's interpreted.)

> Other issues:
>
> 1. I don't think there's anything especially confused about saying there
> can be a lexical and a dymamic variable of the same name. That there
> can be is why
>
> (values x
> (locally (declare (special x))
> x))
>
> can return two different values.

Did you mean to write confused or confusing? If you meant confused then
I agree with you. If you meant confusing then I disagree. The concept
may not be confusing, but the explanations that are bandied about can be
mightily confusing.

> There was a cleanup issue, PROCLAIM-LEXICAL, that would have dealt
> with some of these issues, but it had consequences (such as lexical
> globals) that made enough people reluctant to adopt it.

Here's an idea: define a reader macro for $ that expands into SYMBOL-VALUE.
That would give the following behavior:

(setf x 0) at top level --> error or warning (assignment to non-existant
lexical binding, or assuming dynamic binding is intended and assigning
to $x instead)

(setf $x 0) --> (setf (symbol-value 'x) 0) ; no warning

Now extend the lambda-list syntax to allow variables with names that
are lists beginning with SYMBOL-VALUE, kind of like extending the syntax
of function names to allow names that are lists beginning with SETF.
So instead of:

(lambda (x y) (declare (special y)) (values x y))

you now write:

(lambda (x $y) (values x $y))

In fact, you can now have a lexical and a dynamic binding of a variable
with the same name in the same lambda expression:

(lambda (x $x) (values x $x))

X is always lexical. $X is always dynamic.

This proposal has many advantages:

1. It's backwards-compatible with the existing standard, and provides a
path for deprecating (declare (special ...)) and all the related gunk.

2. It enforces a lexically apparent distinction between references to
lexical and dynamic bindings, kind of like the *...* convention now in
common use. The convention is also compatible with common practice
in the non-Lisp world, which should help non-Lispers feel a little warmer
and fuzzier when transitioning to Lisp.

3. It requires only minimal changes to existing compilers: add a reader
macro, and change the lambda-list processing routines to translate

(let ( ... ((symbol-value x) ...) ...) ...)

into

(let ( ... ( x ...) ...) (declare (special x)) ...)

Hm. I'm starting to think this isn't a half bad idea.

E.

Erik Naggum

unread,
Feb 26, 2000, 3:00:00 AM2/26/00
to
* g...@jpl.nasa.gov (Erann Gat)

| It takes a pretty smart implementation of Common Lisp to actually
| produce this result as presented. In most systems you'll have to

| recompile FOOBAR after DEFVARing X to see the result:

foo was never compiled. there are downsides to compile-only systems.

#:Erik

Reply all
Reply to author
Forward
0 new messages