archives

Block-scope

I've recently been puzzled by what I considered to be a design error in Javascript. Then I realized that Python behaved the same. Finally, I realized that people were aware of the issue: these languages don't have block-scope, the only scoping construct is the function. If you declare a variable inside a loop, the same instance will be used for every iteration, and it will be visible after the end of the loop.

As I said I considered this as a design error; to me, it's not natural at all. I realize that I get this feeling because of other languages that I use, mostly OCaml but also C. The other day I was discussing with somebody, trying to convince him of the awkwardness of this, but he found that normal, said that experienced Javascript programmers know this behaviour, and that he didn't see any reason why one choice is better than the other. So I started to look for a good answer showing that one definition of scoping has much better properties than another, etc. It's not that easy.

Here are the questions that I want to share:
* Anybody knows of (a document explaining) the rationale behind JS or Python's choice?
* What solution do you prefer, and which _solid_ argument would you propose for it?

I couldn't find anything concerning the first question. I found a claim that JS2 would fix that, but it didn't seem right to me when reading the specification draft. Concerning the second question, here are possible answers...

0. Conservatism

Since C/C++/... has block-scope, it would have been wise to keep it the same, and avoid the user's puzzling. Or at least forbid the var declaration inside a block, asking the user to declare it at toplevel in a function, which is equivalent anyway.

1. Expressivity

The more properties one has to reason about a language, the better it is. One such property can be: inserting some expression (under X conditions) in a sequence doesn't change the final result of a program. It can't be true if the expression declares a variable at toplevel -- some people might advocate for the let-in construct at this point. Without block scoping it also isn't true as soon as the expression declares a variable inside a block. So the property is more constrained.

2. Static scoping

Another possibility is to ask for easier static analysis. Without block scoping, the scope gets enriched after a loop which declares a variable, *if there was at least one iteration*. This condition makes the lexical environment runtime-dependent. But well, with or without block-scope, static analysis is just impossible for dynamic languages anyway..

PS: Today I got mail on the r6rs list criticizing the absence of scope for the begin construct. It seems that even Scheme made this choice..