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

Re: Some easy ones (?)



Summary: The "no repeated names" rule removes a potential ambiguity
for let; let* doesn't have that ambiguity..  Since they are different,
exempting let* from the rule merely acknowledges their difference
rather than introducing an exception.  Repeated variable names are
better than some obvious alternatives.

I'll get to &aux and &optional names at the end of this message.


Let* is different from let because it REQUIRES multiple lambda
expressions.  Disallowing repeated names makes almost as much sense as
disallowing shadowing.

There is a reason to forbid repeated names in lambda-expressions (and
therefore let), do, labels, and the like.  That reason is to avoid
ambiguity.

Let* (and possibly do*, I'm not sure about it) with repeated names is
NOT ambiguous.  Pervasive declarations don't make it ambiguous; the
declaration affects the outermost instance of a name.

I use let* and repeated names when I am refining two or more objects
together.  (I also use repeated names when I am successively refining
one object because it's easier to read than composing and allows me to
pass the unrefined object in multiple places to the refining function.)
It lets me use the same descriptive name everywhere for a given class
of object; scoping guarantees that I always have the right one.  For
example:

(let* ((success (build-success code1 success failure))
       (failure (build-failure code2 success failure))
       (success (build-success code3 success failure)))
  <body>)

None of the following are clearer.  Are there clearer alternatives?

(let* ((code1-success (build-success code1 success failure))
       (failure (build-failure code2 success failure))
       (success (build-success code3 success failure)))
  <body>)

(let* ((success (build-success code1 success failure))
       (failure (build-failure code2 success failure)))
  (let ((success (build-success code3 success failure)))
    <body>))

(progn
  (setq success (build-success code1 success failure))
  (setq failure (build-failure code2 success failure))
  (setq success (build-success code3 success failure))
  <body>)

&optional variables fall in a grey area.  If the caller passes enough
arguments, they are just like other variables.  If not, they are sort
of like &aux variables.  Consistency tips the balance, &optional
variables should be handled like non-optional names when it comes to
the no-repeated-names rule.

As to &aux, CLtL says it's a matter of style whether one uses it or
not.  I chose not to so I don't care if repeated names are forbidden
even though they wouldn't be if the programmer used let*.  (It would
be an exception to a useful rule, "all names in a lambda-expression
must be unique", to allow shadowing &aux variables.  I'd rather flush
&aux though.)

-andy
-------