To expand on Jan’s comments, note the difference in disassemblies:
puts RubyVM::InstructionSequence.disasm lambda { eval ‘x = 1’; puts x }
== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>=====
== catch table
| catch type: redo st: 0000 ed: 0028 sp: 0000 cont: 0000
| catch type: next st: 0000 ed: 0028 sp: 0000 cont: 0028
|------------------------------------------------------------------------
0000 trace 1 (
-
0002 putself
0003 putstring “x = 1”
0005 send :eval, 1, nil, 8, ic:0
0011 pop
0012 trace 1
0014 putself
0015 putself
0016 send :x, 0, nil, 24, ic:1
0022 send :puts, 1, nil, 8, ic:2
0028 leave
=> nil
puts RubyVM::InstructionSequence.disasm lambda { x = nil; eval ‘x = 1’;
puts x }
== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>=====
== catch table
| catch type: redo st: 0000 ed: 0030 sp: 0000 cont: 0000
| catch type: next st: 0000 ed: 0030 sp: 0000 cont: 0030
|------------------------------------------------------------------------
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1]
s1)
[ 2] x
0000 trace 1 (
-
0002 putnil
0003 setdynamic x, 0
0006 trace 1
0008 putself
0009 putstring “x = 1”
0011 send :eval, 1, nil, 8, ic:0
0017 pop
0018 trace 1
0020 putself
0021 getdynamic x, 0
0024 send :puts, 1, nil, 8, ic:1
0030 leave
=> nil
In the first instance, the parser decides that, having seen no local x,
it
must be a function call, and so “0016 send :x, 0, nil, 24, ic:1” is
emitted.
In the second, having already seen an x (“0003 setdynamic x, 0”), it
knows
that it is referring to the local var, so it emits “0021 getdynamic x,
0”
instead of a call.
Unfortunately, there’s no in between where it could refer to either a
local
or function, because the compiler needs to know all locally-referable
variables in order to emit the instructions; “setdynamic x, 0” is
actually
“setdynamic 2, 0” (note the ‘local table’ before the instructions in the
second disassembly, and the total lack of same in the first one), which
is
why local variables are so fast; they’re just direct offsets from the
local
frame
pointerhttp://lifegoo.pluskid.org/upload/doc/yarv/yarv_iset.html#detail-1
(“environment
pointer” as of June
2012http://comments.gmane.org/gmane.comp.lang.ruby.cvs/39182
).
So, in short, VM constraints are responsible for this being impossible.
You
could either just say ‘a = b = c = d = … = nil’ before your hash.extract
to
make them findable, or find a possibly “more Ruby” way.
— Arlen