[racket] Nested scope in D vs Racket

From: Shriram Krishnamurthi (sk at cs.brown.edu)
Date: Sat Aug 21 15:21:13 EDT 2010

Your reduction of this guideline to what you claim Hansen preached (I
haven't seen that essay) is unfair.  The D guideline does not say
"don't have nested scope".  It says to not allow lexical re-binding,
which is a much, much finer point.

Given how many languages get this sort of thing just plain wrong, or
even when they get it right the outcome is surprising/unintuitive, it
seems to be a not-bad guideline to language designers to say "Just
don't allow lexical re-binding of lexically bound identifiers unless
you really know what you're doing".

I mean, it's all visible in scope, so renaming is easy; why not just
give it a different name?  It might even be clearer to the reader!

  (let ([it 5])
    (+ ...
       (let ([it 10])
         (... ...

Uh, which `it'?

  (let ([itsy 5])
    (+ ...
       (let ([bitsy 10])
         (... ...

(Aha, not `itsy'!)

Of course, this is bound to create a problem somewhere in a language
as rich as Racket, eg, if a macro wants to capture a name:

  ;; M captures `it'
  (let ([it 3])
    (M ... it ...))
  --> error: lexical re-binding of lexical identifier: it

However, because the masking is lexical, it is trivial to rename the

  (let ([itsy-bitsy 3])
    (M ... it ...))
  --> <some awesome answer>

One could argue this made the program EVEN clearer than in the
previous example, because the visible binding is not the one in use
inside (M ... it ...), and the reader needs to know+remember this.

So, I'm just saying, this doesn't strike me as such an awful
guideline.  It might even be a wise one.

On the other hand, there is one (and just one) situation where I
knowingly and intentionally violate this guideline, and the violation
is defensible as a Good Thing.  Readers are welcome to guess. (-:


Posted on the users mailing list.