[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Binding the same variable twice in a single form



    Date: Thu, 12 Apr 90 13:33 CDT
    From: lgm@ihlpf.att.com

    Let's say I have a function FUNC that returns three values.  In a
    particular situation I need only the third value.  On the
    Symbolics I could write

	    (MULTIPLE-VALUE-BIND (IGNORE IGNORE X) (FUNC)
		    <use X somehow>)

    The question is whether this usage is portable.

No.

    Other Common Lisp implementations may treat IGNORE as an ordinary
    variable name, 

They should treat it as normal.  It's what CLtL says to do.  We're not
conforming on this point--though admittedly many people find this
non-conformance useful.  But, for example, the Common Lisp Developer (to
be available in Release 8.0) will treat IGNORE like a normal variable
(and hence help you spot this problem--and many others).

The intended (CLtL) usage is:

 (MULTIPLE-VALUE-BIND (A B X) (FUNC)
    (DECLARE (IGNORE A B))
    <use X somehow>)

If/when ANSI Common Lisp is ever a reality, you will also be able to 
 (LET ((X (NTH-VALUE 2 (FUNC))))
    <use X somehow>)
In some cases, the usage may be even simpler. e.g., if the usage was
(+ X 3) you may be able to write:
 (+ (NTH-VALUE 2 (FUNC)) 3)
and avoid the MULTIPLE-VALUE-BIND altogether.

Currently (even in Rel8, which I'm using) we don't implement the new
NTH-VALUE, but I just wanted you to know that there was hope for the 
future of this issue.

Also, just for your reference, we tried to convince the other Lisp vendors
that it was worth having LISP:IGNORE be treated specially by the compiler
but we couldn't get enough votes.  If you feel strongly about this issue
and have contact with other vendors, let them know.

As an aside, this problem came up a lot in MACSYMA years ago when I
converted our implementation to be CL-based.  At some point I gave up
and just did (PROCLAIM '(SPECIAL IGNORE))--which is slightly less efficient
but has almost the same effect as telling the compiler to ignore the
variable named IGNORE.  Many compilers don't complain about doubling
a binding, so (MULTIPLE-VALUE-BIND (IGNORE IGNORE X) ...) might then
work just fine (modulo doing two unnecessary special binds :-).

    and
    thereby interpret the expression as binding the same variable
    twice in the same form.

============================================================================
    The Symbolics allows this silently in any
    case, even an obvious one like

	    (LET ((A 3) (A 4)) A)

In the interpreter you don't get warnings about a lot of things.
In the compiler, though, (at least in Rel8, which I'm running now)
you get a warning:

 (defun foo () (let ((a 3) (a 4)) a))
 For Function FOO
   The value of variable A was never used.

This isn't the most intuitive message but partly that's because an
optimization of the trivial bindings is obscuring the normal warning
message you'd get.

 (defun foo () (let ((a (f)) (a (g))) a))
 For Function FOO
   While compiling (LET ((A (F))
			 (A (G)))
		     A):
     Lexical variable A bound twice -- earlier binding will be shadowed

    But do other CL implementations act similarly?  

No. This is an "is an error" situation in CLtL, as it will be in ANSI
CL.  This means that the result is "undefined".  Either the first
binding or the second binding may be used when the error is not
detected, or else a warning or error may occur.

    Does the upcoming
    ANSI standard address this question?

Yes, a number of these issues are more explicit in the standard.
Mind you, more explicit may mean ``explicitly vague''--i.e.,
the standard will say
 ``This is undefined.''
where previously no agreement meant it was undefined only by
omission.  Such is the nature of progress.  At least an explicit
statement should help to highlight the need for people to be concerned
about these issues.