1

This is something strange I've figured out in ruby 1.9.3.

Here is the code:

>> r = true
>> if r
>>   a  = "hello"
>> else
>>   b = "hello"
>> end

Now the value of a is "hello":

>> a
=> "hello"

And strangely the value of b is nil

>> b
=> nil

Since b is nowhere in the scene, it should be undeclared.

Why?

toro2k
  • 19,020
  • 7
  • 64
  • 71
Paritosh Singh
  • 6,288
  • 5
  • 37
  • 56

3 Answers3

3

Variable declarations take effect even if the branch where the assignment takes place is never reached.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • @Patritosh: I just ran your code, then ran `puts b.object_id # => 70364348734500`. As you see, the object `b` was created and given the value `nil`. – Cary Swoveland Jan 17 '14 at 08:19
  • 2
    @CarySwoveland: That's strange. What Ruby implementation are you using? It's not required by the spec, but on all even remotely popular Ruby implementations (MRI, YARV, Rubinius, JRuby, IronRuby, MRuby, Ruby.NET, XRuby, MagLev, MacRuby, Cardinal, Topaz, BlueRuby, Ruby GoLightly, tinyrb), the `object_id` of `nil` is `4`. – Jörg W Mittag Jan 17 '14 at 14:13
  • @Jörg, odd indeed! It should have been `b.object_id # => 8`. (I'm using MRI 2.0.0). So how did I get 70364348734500? It was an IRB gotcha. I had used the variable `b` to test something else earlier, and neglected to check it's value after running the asker's code and `puts b.object_id `. Why didn't I notice something was amiss? No explanation for that. `object_id` of `nil` was [changed to 8](http://stackoverflow.com/questions/15506763/why-was-the-object-id-for-true-and-nil-changed-in-ruby2-0) in 2.0. – Cary Swoveland Jan 17 '14 at 18:04
  • Ah, yes, I forgot about the extra tag bit for flonums in YARV 2.0. (BTW: object IDs are a private internal implementation detail of a particular Ruby implementation. They are not guaranteed to be the same on different implementations. They are not even guaranteed to be the same across several runs of the same program. So, when you say that the ID of `nil` was changed in 2.0, what you specifically mean is that it was changed in *YARV 2.0*, not in *Ruby 2.0*. Ruby 2.0 doesn't make any guarantees about the value of `object_id` for `nil` or any other object.) – Jörg W Mittag Jan 18 '14 at 13:19
  • @Jörg, you are a stickler (a very desirable trait in your profession, imo--I say "your" because for me coding is just a hobby). And thanks for the clarification. – Cary Swoveland Jan 19 '14 at 06:37
3

The reason for this is explained in the Ruby documentation, and it is valid for any version of Ruby, not just 1.9:

The local variable is created when the parser encounters the assignment, not when the assignment occurs.

This means that if the parser sees an assignment in the code it creates the local variable even if the assignment will never really occur. In this case the value referenced by the variable is nil:

if true
  a = 0
else
  b = 0
end

p local_variables
# => [:a, :b]

p a
# => 0

p b
# => nil
toro2k
  • 19,020
  • 7
  • 64
  • 71
2

The local variable is created when the parser encounters the assignment, not when the assignment occurs:

=> foo
# NameError: undefined local variable or method `foo' for main:Object
=> if false
=>   foo = "bar" # does not assign to foo
=> end
=> nil
=> foo
=> nil
Roman Kiselenko
  • 43,210
  • 9
  • 91
  • 103