

Immutability and Blocks, Lambdas and Closures - hanifvirani
http://algorithm.com.au/blog/files/immutability-blocks-lambdas-closures.php

======
ekiru
The real issue is that Python's for construct doesn't create a new lexical
scope for the body.

In either Perl 5 or Perl 6, both of which use mutable variables, the
corresponding code does the right thing (although Perl 5 only does so if you
actually use a newly defined lexical: as in "for my $m ('do', 're', 'mi')
{...}").

Unfortunately, Python's implicit declaration of lexicals means that it would
be difficult to do a for loop with an iteration variable that isn't lexical to
the loop body if that was the default (where would you put the "nonlocal"
statement?).

~~~
masklinn
> The real issue is that Python's for construct doesn't create a new lexical
> scope for the body.

Yes and no, that's what leads the author to notice the "issue", but it does
not actually solve the problem (if closing over a mutable environment is to be
seen as a problem), it just pushes it back.

It can be argued that loops is the most common case where this is a problem
(by quite a long shot) and working around that issue (by creating statement-
level scopes or by using internal iterators [0]) would lead to the vast
majority of users extremely encountering it. But still...

[0] internal iterators being the reason why Smalltalkers never encounter that
issue, and rubyists and modern JS-developers (using Array.prototype.forEach or
equivalent library-specific features) rarely do.

~~~
ekiru
There are certainly other potential issues with closing over mutable
variables. However, if Python's variables were immutable, it would have to
create a new scope for the for body(either with statement-level scopes or by
using internal iterators/higher-order functions instead of for statements).

~~~
masklinn
> There are certainly other potential issues with closing over mutable
> variables.

I don't really like your use of the word variable here. Do you mean objects or
bindings?

> However, if Python's variables were immutable, it would have to create a new
> scope for the for body

(I'm guessing bindings) Sure, but it's not like immutable bindings are
required for that, just go the internal iterator route and you're set for most
cases.

~~~
ekiru
I use "variable" to mean "binding" exclusively.

> Sure, but it's not like immutable bindings are required for that, just go
> the internal iterator route and you're set for most cases.

Right. That's why in my first comment, I said that not creating a new lexical
scope for the loop body is the real issue here. I didn't make it especially
clear that it doesn't matter whether you do that using an internal iterator or
by giving for statements a statement-level scope, but of the two examples I
gave of languages with mutable bindings and the "correct" (IMO) behavior here,
Perl 5 uses the statement-level scope approach, while Perl 6 uses the internal
iteration approach(for is very light syntactic sugar for map).

I believe I misread your previous comment as suggesting that mutability was
the key issue here. In response to that, I wanted to point out that even in a
situation with immutable bindings, one still needs to have each iteration's
binding be a different binding to deal with this case.

------
stdbrouw
This is why CoffeeScript introduced the "do" keyword. I'd have to agree that,
while in Javascript in particular this is considered a rookie mistake, loop
variables not being closed over _is_ a rather confusing phenomenon for
newcomers.

~~~
sharat87
CoffeScript is a very good language, but in my opinion, it should not be an
excuse to not learn and understand such confusing behaviors of javascript. It
will eventually bite any such newcomers. Not that you meant this, just saying.

~~~
evangineer
I guess the best way to view CoffeeScript is to treat it as a form of
shorthand for JavaScript. A more convenient syntax, but you still need to
understand the underlying JavaScript for the purposes of troubleshooting and
performance optimising.

------
glenjamin
Not having a closure around loop blocks is only confusing if you learnt a
language that does have block scope in all cases.

For my part, I always found having block scope inside conditionals to feel
weird.

------
adambyrtek
This problem was solved brilliantly by Clojure. Everything is immutable by
default, and modifications of references happen at explicit points in the
flow, with well-defined semantics.

~~~
Locke1689
To be fair, I believe this behavior was just copied from Lisp, Scheme,
Haskell, and ML.

~~~
adambyrtek
The fundamental ideas come from existing languages, nobody is trying to
contradict that. Clojure builds on the past, but its rich abstractions for
concurrency and persistent data structures make it unique.

~~~
sid0
What "abstractions for concurrency and persistent data structures" does
Clojure have that aren't there in Lisp, Scheme, ML or Haskell?

