In the book Eloquent Ruby (page 21, first edition, sixth printing), the author (Russ Olsen) advocates using the each method instead of
The semantics of the for expression are defined in the ISO Ruby Language Specification like this:
§11.4.1.2.3 The
forexpressionSyntax
- for-expression → for for-variable in expression do-clause end
- for-variable → left-hand-side | multiple-left-hand-side
The expression of a for-expression shall not be a jump-expression.
Semantics
A for-expression is evaluated as follows:
- Evaluate the expression. Let
Obe the resulting value.Let
Ebe the primary-method-invocation of the form primary-expression [no line-terminator here].each do | block-formal-argument-list | block-body end, where the value of the primary-expression isO,the block-formal-argument-list is the for-variable, the block-body is the compound-statement of the do-clause.Evaluate
E, but skip Step c of §11.2.2.The value of the for-expression is the resulting value of the invocation.
Okay, so basically this means that
for for_variable in expression
do_clause
end
is evaluated the same as
O = expression
O.each do |for_variable|
do_clause
end
Aha! But we forgot something! There's this ominous "skip Step c of §11.2.2." thing! So, what does Step c of §11.2.2. say?
- Push an empty set of local variable bindings onto ⟦local-variable-bindings⟧.
Note that Step b
- Set the execution context to
Eb.
is not skipped.
So, a for loop gets its own execution context, which starts out as a copy of the current execution context, but it does not get its own set of local variable bindings. IOW: it gets its own dynamic execution context, but not its own lexical scope.