Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The syntax of LET

30 views
Skip to first unread message

Jeff M.

unread,
Apr 6, 2008, 10:54:03 AM4/6/08
to
I was wondering, is there a particular reason (other than preference
or readability) for chosen syntax of LET and similar forms? Is there a
problem with LET working like so:

(let (x 0 y 1 z 2) (+ x y z))

It seems to me that the above form is easier to parse for the compiler
(admittedly only slightly easier) and the current method is
unnecessarily verbose. But I'm sure there's something I'm mission.
Perhaps a condition that the current form takes care of?

Jeff M.

Ken Tilton

unread,
Apr 6, 2008, 11:32:19 AM4/6/08
to

Jeff M. wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))

You are looking for Arc, which is exploring such alternatives:

http://arclanguage.org/

>
> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.
> Perhaps a condition that the current form takes care of?

I would say the current form takes care of the condition of your
suggested form involving syntax. Syntax just makes things harder. Over
on the Arc site you will find a bunch of people rapidly spiralling down
into Perl, all because they thought the "extra parens" in let were extra
parens.

kenny

--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
in the evening, die content!"
-- Confucius

Pascal Costanza

unread,
Apr 6, 2008, 11:58:37 AM4/6/08
to
Jeff M. wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))

In Common Lisp, (let (x y z) ...) is short for
(let ((x nil) (y nil) (z nil)) ...). The idea is that with (let (x y z)
...) you introduce new variables, but you indicate to readers that you
don't intend any initialization at this stage yet.

With your shorter version, making such intentions clear wouldn't be
possible anymore.

Apart from that, that's a micro issue. There are more important things
to worry about than getting such detailed design issues right. In large
programs, this gets lost in the noise.


Pascal

--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Harald Hanche-Olsen

unread,
Apr 6, 2008, 12:04:58 PM4/6/08
to
+ "Jeff M." <mas...@gmail.com>:

> Is there a problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))

It might be slightly harder to write a macro that builds up a let form
on this form. That is not a very strong reason, but it just might be
one of several reasons for the current choice.

--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
when there is no ground whatsoever for supposing it is true.
-- Bertrand Russell

Pascal Bourguignon

unread,
Apr 6, 2008, 12:06:23 PM4/6/08
to
"Jeff M." <mas...@gmail.com> writes:

Why don't you try?

(shadow 'let)
(defmacro let (bindings &body body)
(assert (evenp (length bindings)))
`(cl:let ,(loop :for (var val) :on bindings :by (function cddr)
:collect (list var val)) ,@body))


C/USER1[103]> (let (x 0 y 1 z 2) (+ x y z))
3

Yep, seems to work well.

--
__Pascal Bourguignon__ http://www.informatimago.com/

ADVISORY: There is an extremely small but nonzero chance that,
through a process known as "tunneling," this product may
spontaneously disappear from its present location and reappear at
any random place in the universe, including your neighbor's
domicile. The manufacturer will not be responsible for any damages
or inconveniences that may result.

Scott Burson

unread,
Apr 6, 2008, 1:31:39 PM4/6/08
to
On Apr 6, 7:54 am, "Jeff M." <mass...@gmail.com> wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms?

The "extra parens" leave room for some useful syntactic extensions. I
have a `let' macro that makes it more convenient to bind variables to
the multiple values of a form, e.g.:

(let ((a b c (foo))) ...)

expands to

(multiple-value-bind (a b c) (foo) ...)

It does some other stuff too. You can find it at

http://common-lisp.net/project/misc-extensions/

-- Scott

Scott Burson

unread,
Apr 6, 2008, 1:33:12 PM4/6/08
to
On Apr 6, 8:32 am, Ken Tilton <kennytil...@optonline.net> wrote:
> Over
> on the Arc site you will find a bunch of people rapidly spiralling down
> into Perl, all because they thought the "extra parens" in let were extra
> parens.

Is the honeymoon over already??

-- Scott

Ron Garret

unread,
Apr 6, 2008, 1:44:48 PM4/6/08
to
In article
<b4f08883-f411-4341...@8g2000hse.googlegroups.com>,
"Jeff M." <mas...@gmail.com> wrote:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))

Nope. The only downside is that if you want to initialize a variable to
NIL you have to do it explicitly. Not a bit loss IMHO.

> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier)

Actually, it's the other way around. Try writing the macro expansion
for both your new LET and the old LET in terms of LAMBDA and you'll see
that your version is actually slightly harder to parse.

> and the current method is unnecessarily verbose.

It certainly is. However, unnecessary verbosity is not necessarily a
bad thing. See http://rondam.blogspot.com/2008/02/z-shrtr-bttr.html

Personally, I've become rather fond of a macro I call BB (for
binding-block) which lets you interleave variable initializations and
code, e.g.:

(bb
x 1
y 2
(foo x y)
:mv (q z) (bratz) ; short for multiple-value-bind
:db (y . z) (frotz) ; short for destructuring-bind
:with open-file (z "foo")
(do-a-bunch-of-stuff ...))

is equivalent to:

(let* ((x 1) (y 2))
(foo x y)
(multiple-value-bind (q z) (bratz)
(destructuring-bind (y . z) (frotz)
(with-open-file (z "foo")
(do-a-bunch-of-stuff ...)))))

You could easily get even more radical than that by having a form that
was like PROGN but implicitly assigned a name to every form, e.g.:

(implicitly-binding-progn
(foo) ; bound to _0
(baz) ; bound to _1
(bar) ; bound to _2
(bratz _0 _1 _2))

Personally I think this is going too far, but the great thing about Lisp
is that you don't need to be limited by my lack of imagination.

rg

Ken Tilton

unread,
Apr 6, 2008, 3:21:51 PM4/6/08
to

Honeymoon? Oh, you mean:

http://smuglispweeny.blogspot.com/2008/02/maybe-i-was-too-hard-on-sohail.html

:)

kenny

"I've never read the rulebook. My job is to catch the ball."
-- Catcher Josh Bard after making a great catch on a foul ball
he might have let drop and then sliding into the dugout, which
by the rules allowed the runners to advance one base costing his
pitcher a possible shutout because there was a runner
on third base.

"My sig is longer than post of my articles."
-- Kenny Tilton

Barry Margolin

unread,
Apr 6, 2008, 3:54:56 PM4/6/08
to

There's a general Lisp philosophy that lists should be used for
grouping. The standard LET syntax makes the grouping of a variable and
its initializer explicit. And as others pointed out, this grouping then
allows for additional syntactic extensions, such as leaving out the
initializer or extending it to multiple values.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***

Kent M Pitman

unread,
Apr 6, 2008, 4:17:18 PM4/6/08
to
"Jeff M." <mas...@gmail.com> writes:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))
>
> It seems to me that the above form is easier to parse for the compiler

Lisp doesn't do "parsing", it does "reading". The reader has no
difficulty with either format.

Once in structure, the question becomes one of grouping, and the grouping
is more natural in LET as it's done because traditionally LET meant little
more than:

(defmacro let (bindings &body forms)
`((lambda ,(mapcar #'first bindings))
(mapcar #'second bindings)))

Using traditional Lisp operators, extracting and assembly the same
information from an alternating list is actually what's harder.

But independent of the difficulty issue, which is minor, most Lisp users
prefer to see the bindings grouped. It makes it easy to grab the pair of
a name and a value and move it to another point in the list. For example,
in:

(let* ((x1 v1) (x2 v2)) ...)
with cursor ----^

you can re-order the two bindings in Emacs by pressing c-m-t. If you
had

(let* (x1 v1 x2 v2) ...)
with cursor --^

and wanted to reorder things, you'd need more operations. Similar truths
with c-m-k, c-m-f, etc. And in some other structure-based editors other
than Emacs, similar things apply.

> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.

[missing]. ;)

> Perhaps a condition that the current form takes care of?

Well, unrelated to the above, there is an additional thing you're
missing which is that

(let (w x y z) ...)

already has a meaning. It means

(let ((w nil) (x nil) (y nil) (z nil)) ...)

although I and some other people tend to use it to mean "I didn't
initialize these yet, and the NIL is only a courtesy initialization,
not something to rely on".

Alex Mizrahi

unread,
Apr 6, 2008, 5:39:25 PM4/6/08
to
KMP> although I and some other people tend to use it to mean "I didn't
KMP> initialize these yet, and the NIL is only a courtesy initialization,
KMP> not something to rely on".

just curious.. is it possible to have unbound lexical variable?
if it's not possible, then why -- is this conceptually wrong in some way, or
just assubed to be not useful?


Joost Diepenmaat

unread,
Apr 6, 2008, 5:42:40 PM4/6/08
to
"Alex Mizrahi" <udod...@users.sourceforge.net> writes:

Unbound variables seem to me to be neither lexial, global or
special. That's (part of) what it means for vars to be unbound, right?

Somebody please correct me if I'm wrong. Cheers.

J.

--
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/

John Thingstad

unread,
Apr 6, 2008, 6:35:20 PM4/6/08
to
PÃ¥ Sun, 06 Apr 2008 23:42:40 +0200, skrev Joost Diepenmaat
<jo...@zeekat.nl>:

> "Alex Mizrahi" <udod...@users.sourceforge.net> writes:
>
>> KMP> although I and some other people tend to use it to mean "I didn't
>> KMP> initialize these yet, and the NIL is only a courtesy
>> initialization,
>> KMP> not something to rely on".
>>
>> just curious.. is it possible to have unbound lexical variable?
>> if it's not possible, then why -- is this conceptually wrong in some
>> way, or
>> just assubed to be not useful?
>
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
>
> Somebody please correct me if I'm wrong. Cheers.
>
> J.
>

Well the variable is assumed special.

(defun silly ()
(print unbound))

But the compiler gives a warning about this.
If you intend to use a special variable include a (declare (special
*variable*)).

Variables declared by let/let* will have have value.
As a style guide I try never declare a variable until I have a reasonable
value to assign to it.
Giving a variable a bogus value like nil if it makes no sense is almost as
bad as not declaring it.

--------------
John Thingstad

Ron Garret

unread,
Apr 6, 2008, 6:38:09 PM4/6/08
to
In article <874paed...@zeekat.nl>,
Joost Diepenmaat <jo...@zeekat.nl> wrote:

> "Alex Mizrahi" <udod...@users.sourceforge.net> writes:
>
> > KMP> although I and some other people tend to use it to mean "I didn't
> > KMP> initialize these yet, and the NIL is only a courtesy initialization,
> > KMP> not something to rely on".
> >
> > just curious.. is it possible to have unbound lexical variable?
> > if it's not possible, then why -- is this conceptually wrong in some way,
> > or
> > just assubed to be not useful?
>
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?

Nope.

> Somebody please correct me if I'm wrong. Cheers.

You're wrong. To understand why start by reading:

http://www.flownet.com/ron/specials.pdf

It so happens that it is not possible to produce an unbound lexical
variable in CL, but this is only because of the way the language is
designed, not because it is inherently impossible or meaningless.

rg

Matthias Benkard

unread,
Apr 6, 2008, 6:38:17 PM4/6/08
to
On 6 Apr., 23:42, Joost Diepenmaat <jo...@zeekat.nl> wrote:
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?

It probably depends on what you mean by a "variable".

In CLHS terms, a special variable need not be bound.

CL-USER> (defvar *abc*)
*ABC*
CL-USER> (boundp '*abc*)
NIL

From CLHS 3.1.2.1.1.1:

"A lexical variable always has a value. There is no operator that
introduces a binding for a lexical variable without giving it an
initial value, nor is there any operator that can make a lexical
variable be unbound."

From CLHS 3.1.2.1.1.2:

"The value part of the binding for a dynamic variable might be empty;
in this case, the dynamic variable is said to have no value, or to be
unbound. A dynamic variable can be made unbound by using makunbound."

Then again, the terminology is a bit weird. It seems that even if a
binding exists for a variable, it (the variable) may still be unbound.

~ Matthias

Joost Diepenmaat

unread,
Apr 6, 2008, 6:48:53 PM4/6/08
to
"John Thingstad" <jpt...@online.no> writes:

> PÃ¥ Sun, 06 Apr 2008 23:42:40 +0200, skrev Joost Diepenmaat

>> Unbound variables seem to me to be neither lexial, global or
>> special. That's (part of) what it means for vars to be unbound, right?
>>
>> Somebody please correct me if I'm wrong. Cheers.
>

> Well the variable is assumed special.
>
> (defun silly ()
> (print unbound))
>
> But the compiler gives a warning about this.
> If you intend to use a special variable include a (declare (special
> *variable*)).

I should have known this. I've seen the warning often enough, and it
sort of makes sense to have an unbound var be special (or at least
global). Anyway, thanks to you and the others who replied.

Cheers,
Joost.

John Thingstad

unread,
Apr 6, 2008, 7:27:02 PM4/6/08
to
PÃ¥ Mon, 07 Apr 2008 00:38:17 +0200, skrev Matthias Benkard
<mulki...@gmail.com>:

>
> From CLHS 3.1.2.1.1.2:
>
> "The value part of the binding for a dynamic variable might be empty;
> in this case, the dynamic variable is said to have no value, or to be
> unbound. A dynamic variable can be made unbound by using makunbound."
>
> Then again, the terminology is a bit weird. It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.
>
> ~ Matthias

Well a global variable is bound to a symbol.
A symbol can have FUNCTION, PACKAGE, PLIST attributes as well as VALUE as
accessed by symbol-name, symbol-package, symbol-plist and symbol-value.
So a makunbound only makes the symbol-value unbound not all the other
attributes.
Note that this means (boundp variable) returns NIL which is different from
(symbol-value variable) returning NIL.

--------------
John Thingstad

John Thingstad

unread,
Apr 6, 2008, 7:30:02 PM4/6/08
to
PÃ¥ Mon, 07 Apr 2008 01:27:02 +0200, skrev John Thingstad
<jpt...@online.no>:

> as accessed by symbol-name, symbol-package, symbol-plist and

symbol-function not symbol-name! symbol-name gives a string denoting the
name of the symbol.

--------------
John Thingstad

Kent M Pitman

unread,
Apr 6, 2008, 7:36:59 PM4/6/08
to
"Alex Mizrahi" <udod...@users.sourceforge.net> writes:

It used to be discussed from time to time and no one ever advanced a
compelling argument for why it's needed. It's part of the heritage of
functional programming languages. You can't get unbound lexicals in
Scheme or ML or Haskell as far as I know either. Either a variable
name has a binding AND a value, or it doesn't have a binding.

So just as there's a theory that all functions return values whether
they want to or not (that is, there's no void type), there's also a
theory that all variables have values whether they want them or not.

Also, efficiency-wise, I suspect it works against speed because (as
I'm thinking about it just now--not something I've thought about in a
while so I may not have all relevant facts at the top of my
consciousness) it means either you have a "sufficiently clever
compiler" capable of adequate flow analysis to be able to not have to
look at every reference to see if it contains the magic unbound marker
OR ELSE it means you have to slow down every reference to the variable
just to see if the variable is bound before you access it.

Mark Wooding

unread,
Apr 6, 2008, 7:41:28 PM4/6/08
to
Joost Diepenmaat <jo...@zeekat.nl> wrote:

> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
>
> Somebody please correct me if I'm wrong. Cheers.

(defvar *special*)
(boundp '*special*) ; => NIL

Common Lisp's concept of bound-ness doesn't quite match up with the
usual one -- it adds an extra requirement of `having a value'.

Certainly, a symbol is always `bound' in the sense that we know where to
find its value -- either it's lexically bound, in which case we pluck
the value out of the appropriate run-time environment frame, or it's
not, in which case we use the symbol's value cell. The complication is
that there might not actually be a proper value there when we find it.

As an aside on implementation, SBCL (and presumably other
implementations) actually works by having a magical not-a-value marker
which it puts in the symbol's value-cell; SLOT-BOUNDP and friends apply
the same concept to the slots of CLOS classes, and in pretty much the
same way (SBCL actually just uses the symbol SB-PCL::..SLOT-UNBOUND.. as
its marker).

Given this state of affairs, there doesn't seem much reason why there
couldn't in principle be `unbound lexical variables'. But checking a
symbol's value-cell for bound-ness takes time, and it was probably
thought that it wasn't worth slowing down access to lexical variables
just because there might be a use for making them be unbound. (That
said, the compiler will be able to notice whether a lexical variable
could be referred to while in an unbound state, so maybe it wouldn't be
such a loss after all. It still doesn't seem particularly useful, and
inventing your own unique magic-marker-value isn't difficult.)

-- [mdw]

Joost Diepenmaat

unread,
Apr 6, 2008, 8:08:04 PM4/6/08
to
Mark Wooding <m...@distorted.org.uk> writes:

> Given this state of affairs, there doesn't seem much reason why there
> couldn't in principle be `unbound lexical variables'. But checking a
> symbol's value-cell for bound-ness takes time, and it was probably
> thought that it wasn't worth slowing down access to lexical variables
> just because there might be a use for making them be unbound. (That
> said, the compiler will be able to notice whether a lexical variable
> could be referred to while in an unbound state, so maybe it wouldn't be
> such a loss after all. It still doesn't seem particularly useful, and
> inventing your own unique magic-marker-value isn't difficult.)

So how, for the sake of argument would an implementation figure out that
an unbound variable would be lexical instead of global, and especially,
what scope the unbound lexical should have?

Kent M Pitman

unread,
Apr 6, 2008, 8:08:52 PM4/6/08
to
Joost Diepenmaat <jo...@zeekat.nl> writes:

> "Alex Mizrahi" <udod...@users.sourceforge.net> writes:
>
> > KMP> although I and some other people tend to use it to mean "I didn't
> > KMP> initialize these yet, and the NIL is only a courtesy initialization,
> > KMP> not something to rely on".
> >
> > just curious.. is it possible to have unbound lexical variable?
> > if it's not possible, then why -- is this conceptually wrong in some way, or
> > just assubed to be not useful?
>
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
>
> Somebody please correct me if I'm wrong. Cheers.

Uh... Not entirely sure what you're saying, so hard to tell if you're
wrong or just wording things oddly or you're leaving something out ...

Notwithstanding the fact that I seem to have only put one definition
of binding in the CLHS glossary, there are really to meanings in
evidence if you look through the document. (There may be a political
fight that prohibited me from putting both meanings, since people
think binding is some sacred term in the functional community, or it
may have been just too complicated to get the nuance right, so maybe
I just feared such a fight. I'm quite sure I was aware of the issue.)

In fact, the word binding sometimes means these two things:

1. The association of a symbol with a binding.

2. The fact of the binding being a usable value.

All lexical variables use binding to mean the first thing. In that
case, unbound means "there is no association between this name and any
lexical binding". That is, (lambda () x) refers to an x that has no
associated lexical binding (and there are not global lexicals, so
unless x was globally special, this variable would be seen as unbound).

By contrast, having previously done (proclaim '(special *x*)) or
(defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
to the value cell of the symbol *x*, and there would really be such a thing,
but it might not contain anything [that is, it might contain a magic value
that the system has to take an extra memory cycle to check for, and which
if present means to signal an unbound variable error rather than return the
value].

Ron Garret

unread,
Apr 6, 2008, 8:15:06 PM4/6/08
to
In article <u4paey...@nhplace.com>,

Not much cleverness is required because this check can be done at
compile time. See http://www.flownet.com/ron/lisp/Lexicons.pdf section
3.4.

rg

Joost Diepenmaat

unread,
Apr 6, 2008, 8:30:32 PM4/6/08
to
Kent M Pitman <pit...@nhplace.com> writes:

> Joost Diepenmaat <jo...@zeekat.nl> writes:
>
>> "Alex Mizrahi" <udod...@users.sourceforge.net> writes:
>>
>> > KMP> although I and some other people tend to use it to mean "I didn't
>> > KMP> initialize these yet, and the NIL is only a courtesy initialization,
>> > KMP> not something to rely on".
>> >
>> > just curious.. is it possible to have unbound lexical variable?
>> > if it's not possible, then why -- is this conceptually wrong in some way, or
>> > just assubed to be not useful?
>>
>> Unbound variables seem to me to be neither lexial, global or
>> special. That's (part of) what it means for vars to be unbound, right?
>>
>> Somebody please correct me if I'm wrong. Cheers.
>
> Uh... Not entirely sure what you're saying, so hard to tell if you're
> wrong or just wording things oddly or you're leaving something out ...

I've already been corrected about this statement in the case of CL
specifically. I mostly meant that *in general* there isn't a definite
way to resolve unboundness, though I think that CL's choice of taking
the "global/special" value is sound, or at least the most unsurprising.

> Notwithstanding the fact that I seem to have only put one definition
> of binding in the CLHS glossary, there are really to meanings in
> evidence if you look through the document. (There may be a political
> fight that prohibited me from putting both meanings, since people
> think binding is some sacred term in the functional community, or it
> may have been just too complicated to get the nuance right, so maybe
> I just feared such a fight. I'm quite sure I was aware of the issue.)
>
> In fact, the word binding sometimes means these two things:
>
> 1. The association of a symbol with a binding.
>
> 2. The fact of the binding being a usable value.

I may be stupid, or not interested in politics, but I just associate
binding with 1. I don't even see how something can have an "unusable
value". I can see how a var can have a useless value, though.

> All lexical variables use binding to mean the first thing. In that
> case, unbound means "there is no association between this name and any
> lexical binding". That is, (lambda () x) refers to an x that has no
> associated lexical binding (and there are not global lexicals, so
> unless x was globally special, this variable would be seen as unbound).

Yes, that's my intuition too, now.

> By contrast, having previously done (proclaim '(special *x*)) or
> (defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
> to the value cell of the symbol *x*, and there would really be such a thing,
> but it might not contain anything [that is, it might contain a magic value
> that the system has to take an extra memory cycle to check for, and which
> if present means to signal an unbound variable error rather than return the
> value].

Ok, I think I'm getting a handle on what you're saying above. Thanks for
taking the time to explain this. I'll sleep on it. :-)

Kent M Pitman

unread,
Apr 6, 2008, 8:43:41 PM4/6/08
to
Matthias Benkard <mulki...@gmail.com> writes:

> On 6 Apr., 23:42, Joost Diepenmaat <jo...@zeekat.nl> wrote:
> > Unbound variables seem to me to be neither lexial, global or
> > special. That's (part of) what it means for vars to be unbound, right?
>
> It probably depends on what you mean by a "variable".
>
> In CLHS terms, a special variable need not be bound.
>
> CL-USER> (defvar *abc*)
> *ABC*
> CL-USER> (boundp '*abc*)
> NIL
>
> From CLHS 3.1.2.1.1.1:
>
> "A lexical variable always has a value. There is no operator that
> introduces a binding for a lexical variable without giving it an
> initial value, nor is there any operator that can make a lexical
> variable be unbound."
>
> From CLHS 3.1.2.1.1.2:
>
> "The value part of the binding for a dynamic variable might be empty;
> in this case, the dynamic variable is said to have no value, or to be
> unbound. A dynamic variable can be made unbound by using makunbound."

Good summary. Expanding a little on these factoids to see how
they play out...

The complication sometimes comes because the place a global variable puts
its value is regarded by some as a binding and not by others, I guess.

The issue is further made subtle by the fact that (let ((x ...)) ...)
for a lexical variable is vaguely like CONS in effect, in that every single
time the let binding is executed, a place [or, at least, the potential for
a place, since the compiler is permitted to optimize it out] is created,
so that although the implementation of DOTIMES is explicitly permitted to
allow:
(mapcar #'funcall
(let ((result '()))
(dotimes (i 3) (push #'(lambda () i) result))
(nreverse result)))
=> (3 3 3)
or
=> (0 1 2)
you can introduce a LET to clarify your intent, and then can reliably produce
distinct closures for each iteration, as in:
(mapcar #'funcall
(let ((result '()))
(dotimes (i 3) (let ((i i)) (push #'(lambda () i) result)))
(nreverse result)))
=> (0 1 2)
will definitely produce distinct closures for each iteration.

However, a binding of a special variable, by contrast, because it does not
make a new binding every time--rather, it uses the same binding every time.

(let ((i 'outer))
(declare (special i))
(loop repeat 10 collect
(let ((randomly (zerop (random 2))))
(progv (if randomly (list 'i) '())
(if randomly (list 'inner) '())
;; Sometimes this variable I will refer to an inner
;; special binding, and sometimes not. But the variable
;; will be a special reference to i in either case, and
;; the reason this "works" is that "rebinding" the special
;; variable doesn't change what the special variable refers
;; to.
i))))
=> (INNER INNER OUTER OUTER INNER OUTER OUTER OUTER INNER OUTER)

In effect, to do the same thing lexically, you have to do:

(let ((i 'outer))
(loop repeat 10 collect
(let ((randomly (zerop (random 2))))
(if randomly
(let ((i 'inner)) i)
i))))
=> (INNER OUTER OUTER INNER OUTER INNER INNER OUTER OUTER INNER)

That is, there is no way to lexical bind i provisionally and yet to
use the selfsame reference to i to refer to either the inner or outer
... you either have to talk about a reference to i that is inside the
lexical binding or you have to talk about a different reference to i
that is not.

I hope this is clarifying something for people and not just confusing them.
It was hard coming up with examples to illustrate the subtlety of the issue,
but the issue is, in fact, there.

> Then again, the terminology is a bit weird. It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.

Agreed. Fixing this in the spec would have required making an
incompatible change to the bifurcated usage that was heavily
predominant in the Lisp community. I wasn't up to making such a
complicated change, though I probably should have made a more modest
change by adding a modifier, as I did with separating "boolean" from
"generalized boolean" ... e.g., making up some new terms like
"lexical bindings" vs "runtime bindings" might have helped. It caused
quite a firestorm when I did that for generalized boolean, but it was
probably good because it exposed longstanding confusions that some
people had had. Probably there are people with similarly longstanding
confusions about bindings as the result of the wording I chose, and as
a result of my not identifying the fact of two bindings. Ah well.
Spilled milk.

Kent M Pitman

unread,
Apr 6, 2008, 11:09:20 PM4/6/08
to
Joost Diepenmaat <jo...@zeekat.nl> writes:

The classification of variables into lexical and global are things that
can be done statically. A brief explanation of the issue is in the
background of this issue, which was a failing proposal for CL to acquire
toplevel lexical variables:

http://www.nhplace.com/kent/CL/Issues/proclaim-lexical.html

Ron Garret

unread,
Apr 7, 2008, 3:22:54 AM4/7/08
to
In article <ur6diw...@nhplace.com>,

Kent M Pitman <pit...@nhplace.com> wrote:

This might be a better example:

(let ((i 0))


(declare (special i))
(loop repeat 10 collect
(let ((randomly (zerop (random 2))))
(progv (if randomly (list 'i) '())

(if randomly (list 100) '())
(incf i)))))

In general to make an illustrative example having to do with bindings
you have to have mutation. Otherwise it's impossible to distinguish
between bindings and values.

> > Then again, the terminology is a bit weird. It seems that even if a
> > binding exists for a variable, it (the variable) may still be unbound.
>
> Agreed.

Huh?!? Under what circumstances can a variable have a binding and yet
be unbound?

rg

Ron Garret

unread,
Apr 7, 2008, 3:29:39 AM4/7/08
to
In article <uzls6w...@nhplace.com>,

Kent M Pitman <pit...@nhplace.com> wrote:

> That is, (lambda () x) refers to an x that has no
> associated lexical binding (and there are not global lexicals, so
> unless x was globally special, this variable would be seen as unbound).
>
> By contrast, having previously done (proclaim '(special *x*)) or
> (defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
> to the value cell of the symbol *x*, and there would really be such a thing,
> but it might not contain anything [that is, it might contain a magic value
> that the system has to take an extra memory cycle to check for, and which
> if present means to signal an unbound variable error rather than return the
> value].

Most implementations will actually allow you to provide a binding for a
free global reference after the fact and it will still do the "right
thing" (for some value of "right"):

? (setf f (lambda () x))
;Compiler warnings :
; Undeclared free variable X, in an anonymous lambda form.
#<Anonymous Function #x3000419FD72F>
? (funcall f)
> Error: Unbound variable: X
> While executing: #<Anonymous Function #x3000419FD72F>, in process Listener(111).
> Type :GO to continue, :POP to abort, :R for a list of available restarts.
> If continued: Retry getting the value of X.
> Type :? for other options.
1>
? (defvar x 1)
X
? (funcall f)
1
?

That is, most implementations will assume that, because there are no
global lexicals, any free reference is a special reference even if it
has not been explicitly declared as such.

rg

kod...@eurogaran.com

unread,
Apr 7, 2008, 10:29:12 AM4/7/08
to
> I mostly meant that *in general* there isn't a definite
> way to resolve unboundness
It were nice that garbage collection would be also exerted on symbols -
not only on data- so any unbound symbol (without function or any other
value) could be reclaimed and disappear from the environment,
including the results of doing (do-all-symbols) and the like.

Kent M Pitman

unread,
Apr 7, 2008, 11:19:38 AM4/7/08
to
Ron Garret <rNOS...@flownet.com> writes:

> This might be a better example:
>
> (let ((i 0))
> (declare (special i))
> (loop repeat 10 collect
> (let ((randomly (zerop (random 2))))
> (progv (if randomly (list 'i) '())
> (if randomly (list 100) '())
> (incf i)))))
>
> In general to make an illustrative example having to do with bindings
> you have to have mutation. Otherwise it's impossible to distinguish
> between bindings and values.

I get a different thing out of the implementation than you do.

CL does not have multiple threads, so the example I'll give is not threadsafe.
You'd need to implement DYNAMIC-LET differently for multithreading. But I
need a way to talk about that behavior, so I'm going to talk about it the
way that allows me to point out that your example doesn't necessarily change
the binding.

If you didn't have multithreading or PROGV, you could implement PROGV thus;
moreover, I would argue this is what some implementations do, other than a
bit of stack annotation so they can do the unwinds and winds on process
switch.

(defvar *unbound-marker* (list '*unbound-marker*))

(defun evaluate-for-my-progv (vars)
(loop for var in vars
collect (if (boundp var)
(symbol-value var)
*unbound-marker*)))

(defun assign-for-my-progv (vars vals)
(loop for var in vars
for val in vals
do (if (eq val *unbound-marker*)
(makunbound var)
(setf (symbol-value var) val))))

(defmacro my-progv (vars-form vals-form &body forms)
(let ((vars-var (gensym "VARS"))
(new-vals-var (gensym "NEW-VALS"))
(old-vals-var (gensym "OLD-VALS")))
`(let* ((,vars-var ,vars-form)
(,new-vals-var ,vals-form)
(,old-vals-var (evaluate-for-my-progv ,vars-var)))
(unwind-protect (progn
(assign-for-my-progv ,vars-var ,new-vals-var)
,@forms)
(assign-for-my-progv ,vars-var ,old-vals-var)))))

Now if you run this, you'll see that PROGV does not change the binding, it
changes the value.

(let ((i 0))
(declare (special i))
(loop repeat 10 collect
(let ((randomly (zerop (random 2))))
(progv (if randomly (list 'i) '())
(if randomly (list 100) '())
(incf i)))))

=> (1 101 2 101 101 101 101 3 4 5)

(let ((i 0))
(declare (special i))
(loop repeat 10 collect
(let ((randomly (zerop (random 2))))

(my-progv (if randomly (list 'i) '())


(if randomly (list 100) '())
(incf i)))))

=> (1 101 2 3 101 4 101 101 5 6)

Moreover:

(boundp 'foo)
=> NIL

(my-progv '(foo) '(3) (boundp 'foo))
=> T

(boundp 'foo)
=> NIL

And yet all those FOO's refer to the same cell. In the working view I have,
special variables always refer to the same location, and only the values get
shuffled. In your view, new locations are created.

(I'm kind of under the weather today, so my brain isn't at 100% capacity,
but I think if I thought harder about it I'd tell you that this issue was
just a restatement of the issue of shallow vs deep binding, upon which as
I recall CL doesn't really take a position...)

In any case, the model supports both your way of thinking about it
(that there are distinct bindings) and mine (that there are not).

> > > Then again, the terminology is a bit weird. It seems that even if a
> > > binding exists for a variable, it (the variable) may still be unbound.
> >
> > Agreed.
>
> Huh?!? Under what circumstances can a variable have a binding and yet
> be unbound?

It depends on what you mean by binding. My whole point is that the behavior
supports more than one theory of what a binding is.

Ron Garret

unread,
Apr 7, 2008, 1:36:05 PM4/7/08
to
In article <uk5j97...@nhplace.com>,

Kent M Pitman <pit...@nhplace.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > This might be a better example:
> >
> > (let ((i 0))
> > (declare (special i))
> > (loop repeat 10 collect
> > (let ((randomly (zerop (random 2))))
> > (progv (if randomly (list 'i) '())
> > (if randomly (list 100) '())
> > (incf i)))))
> >
> > In general to make an illustrative example having to do with bindings
> > you have to have mutation. Otherwise it's impossible to distinguish
> > between bindings and values.
>
> I get a different thing out of the implementation than you do.
>
> CL does not have multiple threads

Oh dear, not this again. Every major implementation of CL except one
(CLisp) has threads, and modern programming pretty much demands it. If
you're going to talk about CL in the abstract IMHO you need to assume
threads, and treat the single-threaded case as a special case
optimization.

It is well known that in a single-threaded environment (and ONLY in a
single-threaded environment), dynamic binding can be implemented as
mutation. But IMHO that is not very interesting, and making the
observation generally causes more confusion than it alleviates.

> > > > Then again, the terminology is a bit weird. It seems that even if a
> > > > binding exists for a variable, it (the variable) may still be unbound.
> > >
> > > Agreed.
> >
> > Huh?!? Under what circumstances can a variable have a binding and yet
> > be unbound?
>
> It depends on what you mean by binding.

The meaning of binding is not subject to debate. It is defined in the
standard:

binding n. an association between a name and that which the name
denotes. ``A lexical binding is a lexical association between a name and
its value.'' When the term binding is qualified by the name of a
namespace, such as ``variable'' or ``function,'' it restricts the
binding to the indicated namespace, as in: ``let establishes variable
bindings.'' or ``let establishes bindings of variables.''

UNBOUND is likewise defined:

unbound adj. not having an associated denotation in a binding. See bound.

So by definition (it seems to me) to be unbound is to not have a binding.


> My whole point is that the behavior
> supports more than one theory of what a binding is.

That may well be, but the standard does not.

rg

Pascal Costanza

unread,
Apr 7, 2008, 4:14:02 PM4/7/08
to

No, you can actually implement it using mutation in multi-threaded
environments as well, provided that the respective bindings are
guaranteed to be thread-local.

See http://home.pipeline.com/~hbaker1/ShallowArrays.html for example.


Pascal

--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Kent M Pitman

unread,
Apr 7, 2008, 6:12:13 PM4/7/08
to
Pascal Costanza <p...@p-cos.net> writes:

> Ron Garret wrote:
> > In article <uk5j97...@nhplace.com>,
> > Kent M Pitman <pit...@nhplace.com> wrote:
> >
> >> Ron Garret <rNOS...@flownet.com> writes:
> > It is well known that in a single-threaded environment (and ONLY in
> > a single-threaded environment), dynamic binding can be implemented
> > as mutation. But IMHO that is not very interesting, and making the
> > observation generally causes more confusion than it alleviates.
>
> No, you can actually implement it using mutation in multi-threaded
> environments as well, provided that the respective bindings are
> guaranteed to be thread-local.

Indeed. My point was not to say that what I was saying was useful
only in single-threaded lisps, but rather to say the notation in which
I was trying to speak was chosen to take advantage of words that we all
already knew, so that people not familiar with multithreading issues
could usefully read about this and reason about it.

Bringing in multithreading creates implementation challenges, but not
insurmountable ones, just ones that are (I think) irrelevant to the
current discussion and to the point I was trying to make.

In particular, I wasn't trying to write a proof using my chosen notation,
just to illustrate the concept well enough for Ron to know what I was
speaking about. From there, he can either choose to say he understands
or not. I'm not trying to say he has to think like me, I'm saying he has
the choice to either understand me or to choose not to. But I've done my
part in making my meaning clear.

Thanks for this cross-reference, Pascal.

Pascal Costanza

unread,
Apr 7, 2008, 7:03:50 PM4/7/08
to

The question is what unboundness is typically used for. I see two uses:

+ To make it explicit that a variable hasn't been initialized yet.
Reading it will throw an exception (and not just return nil, as other
languages would, which will make initialization errors occur only much
later and make them much harder to debug).

+ In CLOS objects, slot unboundness can additionally be used to perform
lazy initialization, by defining methods on slot-unbound. (Very useful!
Would actually be useful for global variables as well.)

These two use cases make sense especially for global variables and CLOS
slots because the code that first uses a particular global variable or a
particular slot may be located in a completely different part of some
source code then the respective variable definition / object
instantiation. Having an extra mechanism to indicate uninitialized use
early is helpful because it may otherwise be very hard to track down
what happened.

However, for lexical variables, the only code that can actually read and
write them is textually enclosed. Since it's a good rule of thumb to
keep function definitions small, it should generally be relatively
straightforward to detect whether a variable has been properly
initialized before its first use, and implementing lazy initialization
mechanisms for lexical variables is also not rocket science.

That's just a guess why unboundness is not so useful for lexical
variables, but it seems to me to make sense.

Ron Garret

unread,
Apr 7, 2008, 7:38:01 PM4/7/08
to
In article <uwsn99...@nhplace.com>,

I understand (or at least I think I do). But I think you're wrong, for
reasons that I admittedly did not explain very well. Let me try again.

>
> > See http://home.pipeline.com/~hbaker1/ShallowArrays.html for example.
>
> Thanks for this cross-reference, Pascal.

First let me say that I, er, misspoke (if you'll pardon the Clintonian
weaseling) when I wrote that dynamic binding can only be implemented as
mutation in a single-threaded environment. What I should have said (and
what I actually meant but didn't actually say) was that it can be
implemented as mutation when (and only when) there is a one-to-one
correspondence between bindings and threads (which is, I believe,
equivalent to what Pascal meant when he wrote "bindings are guaranteed
to be thread-local.")

Second, let me make sure that we're on the same page about what exactly
is at issue here. What I think we're talking about is the claim that:

"even if a binding exists for a variable, it (the variable) may still be
unbound."

This was originally written by Matthias Benkard, and you subsequently
agreed with it.

I disagree with this statement. Here are my arguments.

Argument #1 is a simple appeal to the definitions of the words "unbound"
and "binding" in the ANSI spec, and to observe that BY DEFINITION if a
binding exists for a variable it cannot be unbound.

I presume that the counter to this argument is to cite the phraseology
from 3.1.2.1.1.2:

"The value part of the binding for a dynamic variable might be empty; in
this case, the dynamic variable is said to have no value, or to be
unbound."

Let us refer to this sentence as "sentence X."

I claim that sentence X is best regarded as a bug in the spec. For one
thing, there is no such thing as "the value part of a binding." The
word "value" is not part of the definition of "binding." One might
infer that "value" is a synonym for "that which the name denotes" in
which case "binding" means "an association between a value" which makes
a certain amount of sense and is consistent with common usage, but then
"the value part [being] empty" is non-sensical.

Argument #2 is to refute your MY-PROGV example. My understanding of
MY-PROGV is that it is intended to illustrate that being "unbound" can
be implemented by actually assigning a storage location for a variable
and filling that storage location with a special value that indicates
unboundedness. (Please correct me if I'm wrong about that.) But it
seems to me that this is just an implementation hack, and has nothing to
do with correctness according to the spec.

To see this, consider a compiler that emits code for lexical bindings
that operates thusly:

1. Adjust the stack pointer to allocate a block of memory on the stack
to contain the values of the lexical bindings

2. Compute the values of the lexical bindings and store them in the
appropriate places on the stack

The fact that in between steps 1 and 2 there is a time during which
those lexical bindings "exist" (in some sense of the word) but are not
yet "bound" (in some sense of the word) does not change the fact that
ACCORDING TO THE SPEC lexical bindings are ALWAYS bound. The
implementation is not incorrect, but the fact that these "unbound
bindings" "exist" in some sense at some point in time does not change
the fact that the abstract model as specified by the spec does not admit
these "unbound bindings."

In any case, I see nothing to be gained except confusion to treat
sentence X as anything but a bug.

rg

Pascal Costanza

unread,
Apr 7, 2008, 7:59:40 PM4/7/08
to
Pascal Costanza wrote:
> However, for lexical variables, the only code that can actually read and
> write them is textually enclosed. Since it's a good rule of thumb to
> keep function definitions small, it should generally be relatively
> straightforward to detect whether a variable has been properly
> initialized before its first use, and implementing lazy initialization
> mechanisms for lexical variables is also not rocket science.
>
> That's just a guess why unboundness is not so useful for lexical
> variables, but it seems to me to make sense.

To wit:
(defvar %unbound% (list 'unbound))

(defun prepare-binding (binding)
(etypecase binding
(symbol (list binding %unbound%))
(cons (assert (car binding))
(assert (null (cddr binding)))
(list (first binding)
(if (rest binding)
(second binding)
%unbound%)))))

(defun parse-bindings (bindings)
(loop for binding in bindings
for (var expr) = (prepare-binding binding)
collect var into vars
collect (copy-symbol var) into ivars
collect expr into exprs
finally (return (values vars ivars exprs))))

(defmacro ulet ((&rest bindings) &body body)
(multiple-value-bind
(vars ivars exprs)
(parse-bindings bindings)
`(let ,(loop for ivar in ivars
collect `(,ivar %unbound%))
(flet ,(loop for ivar in ivars
collect `((setf ,ivar) (new-value)
(setf ,ivar new-value)))
(flet
,(loop
for var in vars
for ivar in ivars
for expr in exprs
collect `(,ivar ()
(if (eq ,ivar %unbound%)
,(if (eq expr %unbound%)
`(error "Unbound variable ~S." ',var)
expr)
,ivar)))
(symbol-macrolet ,(loop for var in vars
for ivar in ivars
collect `(,var (,ivar)))
,@body))))))


> (ulet ((x (print 42))
(y (print 88)))
y)

88
88

> (ulet (x y) y)

Error: Unbound variable Y.

> (ulet ((x (print 42))
(y (print 88)))
(setq x 111)
(+ x y))

88
199

Ron Garret

unread,
Apr 7, 2008, 9:15:45 PM4/7/08
to
In article <65vqrcF...@mid.individual.net>,
Pascal Costanza <p...@p-cos.net> wrote:

Also:

? (ulet (x) (print (nth-value 1 (ignore-errors x))) (setf x 1) x)

#<SIMPLE-ERROR #x3000419EB41D>
1
?

rg

Barry Margolin

unread,
Apr 7, 2008, 9:38:08 PM4/7/08
to
In article
<b1ce36e4-f74c-4c3e...@a5g2000prg.googlegroups.com>,
Matthias Benkard <mulki...@gmail.com> wrote:

> Then again, the terminology is a bit weird. It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.

The word "binding" is ambiguous. Sometimes it means the connection
between a name and a storage location, while other times it refers to
the contents of the storage location. "A binding exists" refers to the
first sense, "may still be unbound" refers to the second.

The appropriate sense can almost always be distinguished from the
context.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***

Kent M Pitman

unread,
Apr 7, 2008, 10:57:10 PM4/7/08
to
Ron Garret <rNOS...@flownet.com> writes:

> Argument #1 is a simple appeal to the definitions of the words "unbound"
> and "binding" in the ANSI spec, and to observe that BY DEFINITION if a
> binding exists for a variable it cannot be unbound.

My whole point was to explain BOUNDP and MAKUNBOUND in ways I've found to
match common sense.

Implementationally, these functions do not, in all implementations,
test for an absent value cell or remove the value cell. My impression
is that in some impelmentations, they just store a marker in the cell
saying "actually, this isn't bound after all even though there's a
binding here".

And so that's how I think about it. You, of course, may choose not to.

> I presume that the counter to this argument is to cite the phraseology
> from 3.1.2.1.1.2:
>
> "The value part of the binding for a dynamic variable might be empty; in
> this case, the dynamic variable is said to have no value, or to be
> unbound."
>
> Let us refer to this sentence as "sentence X."
>
> I claim that sentence X is best regarded as a bug in the spec.

Ok. But you're appearing elsewhere to be insisting that the wording
of the spec (in the form of the definition of binding) must be taken
as gospel truth and that I'm not allowed to infer my own wording
(note: not my own semantics, merely my own way of talking about the
semantics everyone seems to agree on). I like to use certain the term
binding more flexibly than the spec does, and I think that no harm
comes of it.

I also, incidentally, like referring to the value cell and the
function cell as slots in symbols, even though I was forbidden (in
lengthy arguments with the committee) from expressing it that way in
the spec. People seemed to fear that if I wrote the word slot, some
implementation woudl be forced to implement them that way, just in
case someone core dumped the thing and looked inside to make sure you
were wasting space. To me, it made no difference because
implementations are free to optimize what there is nothing to prevent,
but to some people this was an issue of serious importance.

I've been thinking about bindings as I have for 30 years of Lisp use
in a variety of dialects and it hasn't caused me to get confused writing
programs, so I guess I think the notion holds up under stress in at least
one worked use-case. Your mileage may, of course, vary.

You can argue all you want that I'm wrong. I'm comfortable with that.
Maybe some people will even believe you. I'm comfortable with that, too.
I don't have a goal of convincing you. I only had a goal to say I
disagree with you if you say there's only one way to view this--there isn't.
I've articulated another way. You don't like it, I can see that. But
that's ok. I've met my goal of getting my opinion onto the record.

> Argument #2 is to refute your MY-PROGV example. My understanding of
> MY-PROGV is that it is intended to illustrate that being "unbound" can
> be implemented by actually assigning a storage location for a variable
> and filling that storage location with a special value that indicates
> unboundedness. (Please correct me if I'm wrong about that.)

The unboundedness is implemented by MAKUNBOUND. I have no idea how
MAKUNBOUND does it. What I did was query BOUNDP, keep a marker in
another variable, and then restore the value via MAKUNBOUND. That was
merely for the chance to show how it could be done, not to say it's
done any particular way.

> But it
> seems to me that this is just an implementation hack, and has nothing to
> do with correctness according to the spec.

None of this has anything to do with correctness according to the
spec. As I recall, the spec was specifically written to not take
sides on the shallow/deep binding issue, and my whole point is that
it's left to implementations to sort out.

> To see this, consider a compiler that emits code for lexical bindings
> that operates thusly:
>
> 1. Adjust the stack pointer to allocate a block of memory on the stack
> to contain the values of the lexical bindings
>
> 2. Compute the values of the lexical bindings and store them in the
> appropriate places on the stack
>
> The fact that in between steps 1 and 2 there is a time during which
> those lexical bindings "exist" (in some sense of the word) but are not
> yet "bound" (in some sense of the word) does not change the fact that
> ACCORDING TO THE SPEC lexical bindings are ALWAYS bound.

Certainly. I don't make any such claim. All of my remarks are about the
abstractions, which are neutral as to implementation. It's you, not me,
that I perceive to be saying that things have to be implemented a certain
way. I grant you that there are often pragmatic considerations that lead
in certain directions, but my point is that the spec doesn't really require
it. And my further point is that I happen to like thinking about bindings
differently than you do, and don't find it leads to any problem.

Discussing terminology rather than effect seems odd to me. No harm comes
from my interpretation of what a binding is. You seem to disagree. I doubt
you can show an example where it actually matters. This starts to remind
me of http://xkcd.com/171/

> The
> implementation is not incorrect, but the fact that these "unbound
> bindings" "exist" in some sense at some point in time does not change
> the fact that the abstract model as specified by the spec does not admit
> these "unbound bindings."

Things you can't access don't make any difference.

> In any case, I see nothing to be gained except confusion to treat
> sentence X as anything but a bug.

As I said, I disagree. And now I'm repeating myself. So I'll wind this
down.

Is there anything more to be learned here other than that we each have our
reasons to believe what we believe and that it probably doesn't make either
of us unable to get work done?

Ron Garret

unread,
Apr 8, 2008, 12:58:44 AM4/8/08
to
In article <ufxtxq...@nhplace.com>,

Kent M Pitman <pit...@nhplace.com> wrote:

> I like to use certain the term
> binding more flexibly than the spec does, and I think that no harm
> comes of it.

That is what I disagree with. I think harm does come of it, in the form
of confusion, particularly among people with less experience in the
language than you or I have.

> I've been thinking about bindings as I have for 30 years of Lisp use
> in a variety of dialects and it hasn't caused me to get confused writing
> programs, so I guess I think the notion holds up under stress in at least
> one worked use-case. Your mileage may, of course, vary.

It's a common affliction in many language communities to think that
because the people who have been using the language for a long time have
been able to integrate some confusing idea into their thought patterns
that no harm comes from promulgating that confusion. The C++ world
suffers from this more than the CL world does, but CL suffers from it
nonetheless. The longer one has studied a given language the more one
loses the ability to diagnose this affliction.

Some people actually think that this sort of confusion is a feature
because it keeps out the riffraff. I respectfully dissent.

> You can argue all you want that I'm wrong. I'm comfortable with that.

Glad to hear it :-)

> Maybe some people will even believe you. I'm comfortable with that, too.
> I don't have a goal of convincing you.

Well, I do have a goal of convincing you. People listen to you, and I
think you actively harm the community when newbies hear you say things
like, "Yeah, a variable can have a binding but still be unbound." That
just reinforces the prejudice that some people have that CL sucks, and I
think the community in the long run suffers for it.

> I only had a goal to say I
> disagree with you if you say there's only one way to view this--there isn't.

I do not say that. What I am saying is that it is less confusing to say
that "having a binding" and "bound" mean the same thing, period, end of
story, despite the fact that it is possible to implement dynamic binding
in such a way that behind the scenes a dynamic variable still "has a
binding" in some sense after calling MAKUNBOUND on it.


> It's you, not me,
> that I perceive to be saying that things have to be implemented a certain
> way.

I am not arguing for a particular implementation. What I am arguing for
is particular rhetoric.


> I grant you that there are often pragmatic considerations that lead
> in certain directions, but my point is that the spec doesn't really require
> it. And my further point is that I happen to like thinking about bindings
> differently than you do, and don't find it leads to any problem.
>
> Discussing terminology rather than effect seems odd to me. No harm comes
> from my interpretation of what a binding is. You seem to disagree. I doubt
> you can show an example where it actually matters. This starts to remind
> me of http://xkcd.com/171/

Funny, I could have cited the same cartoon to support my position.

I say, "If a variable has a binding it is bound." Period, end of story.

You say, "If a variable has a binding, it still might be unbound if, for
example, the binding contains a privileged value that indicates that it
is unbound."

To which I say, "What does all the extra complexity of your narrative
buy you?"

And you respond ... ?


> > The
> > implementation is not incorrect, but the fact that these "unbound
> > bindings" "exist" in some sense at some point in time does not change
> > the fact that the abstract model as specified by the spec does not admit
> > these "unbound bindings."
>
> Things you can't access don't make any difference.

Yes! Exactly!


> > In any case, I see nothing to be gained except confusion to treat
> > sentence X as anything but a bug.
>
> As I said, I disagree. And now I'm repeating myself. So I'll wind this
> down.
>
> Is there anything more to be learned here other than that we each have our
> reasons to believe what we believe and that it probably doesn't make either
> of us unable to get work done?

Yes, I think there is. This is not about you and me. This is about the
OP and all the others like him who are scratching their heads trying to
figure out how a variable with a binding can be unbound, and why it
matters.

rg

Pascal Costanza

unread,
Apr 8, 2008, 3:50:39 AM4/8/08
to

Yes, of course. From the HyperSpec:

"ignore-errors executes forms in a dynamic environment where a handler
for conditions of type error has been established; if invoked, it
handles such conditions by returning two values, nil and the condition
that was signaled, from the ignore-errors form."

Ron Garret

unread,
Apr 8, 2008, 12:20:59 PM4/8/08
to
In article <660meeF...@mid.individual.net>,
Pascal Costanza <p...@p-cos.net> wrote:

Right. My point was just to illustrate that in that case X is actually
unbound (or at least behaves as if it is unbound) until you assign a
value to it, whereupon it becomes bound.

Symbol macros are really quite cool.

rg

0 new messages