This question already has answers here:
Closed 6 years ago.
The following ruby statement will result in x
being "defined" (i.e. defined(x)
returning "local-variable"
even if it is undefined prior to execution of this code and even though the assignment is not performed:
x = 1 if false
Specifically, the x
local variable will be set to nil
. The behavior is similar for never-executed assignments subject to while false
and until false
clauses. You can verify this in either irb or running ruby on some code fragment.
My question is twofold:
- Is this behavior documented anywhere?
- Is there a rationale for this behavior documented anywhere?
Here's a bit of an insight from the compiler. This is what Ruby 2.0.0 translates x = 1 if false; puts x; puts y
into (before any code is executed):
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] x
0000 trace 1 ( 1)
0002 jump 7
0004 putobject_OP_INT2FIX_O_1_C_
0005 setlocal_OP__WC__0 2
0007 trace 1
0009 putself
0010 getlocal_OP__WC__0 2
0012 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0014 pop
0015 trace 1
0017 putself
0018 putself
0019 opt_send_simple <callinfo!mid:y, argc:0, FCALL|VCALL|ARGS_SKIP>
0021 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0023 leave
You can see that the local table allocates its slot 2
to the local variable x
. The assignment itself (putobject
, setlocal 2
) is skipped over by jump 7
. puts x
thus fetches the slot 2
and calls puts
; however, since y
is not recognised as a local variable either in this scope or a higher one, it is thought it might be a method, really, almost as if you had written puts(y())
. At execution time, y
cannot be resolved, and the error is raised.