In Ruby, why does nil[1]=1 evaluate to nil?
Asked Answered
M

1

9

For example:

nil[1]     #=> NoMethodError
nil[1]=1   #=> nil

It's not just syntax, as it happens with variables too:

a = nil
a[1]       #=> NoMethodError
a[1]=1     #=> nil

Oddly:

nil.method(:[]=)   #=> NameError
[].method(:[]=)    #=> #<Method...>

Ruby 2.3.0p0

Milkwhite answered 24/4, 2016 at 21:36 Comment(9)
Can't reproduce on Ruby 2.2.4. Maybe a new feature or a bug in your version?Tallage
Weird... Maybe it's a bug.Insignia
I can only reproduce this in Ruby 2.3.0 and I'm going to presume it's a bug. It might be worth checking the bug tracker for this issue.Dyche
Probably it is fixed already. Cannot be reproduced on ruby 2.3.0p71 (2016-03-30 revision 54426).Constructivism
I believe the fix was reported here ("unexpected safe call"). larsch, how did you happen to stumble onto that? Everyone, raises your glasses! It's not everyday that a suspected bug turns out to actually be a bug.Uranic
This is why we avoid the latest versionBreakout
I simple had an instance variable @idx = Hash.new that I was trying to use as @index[key] = value. The unittest was failing in strange ways because the assignment didn't fail on the nil value.Milkwhite
@CarySwoveland Do you want to post that info as an answer so I can mark this question as a duplicate?Jacquelinjacqueline
Thanks, @Jordan, but I'd prefer to leave it as a comment.Uranic
P
1

Some random findings: [only in Ruby 2.3.0p0]

The method doesn't seem to exist:

nil.method(:[]=)      #=> NameError: undefined method `[]='
nil.respond_to?(:[]=) #=> false

And you can't invoke it using send:

nil.send(:[]=)        #=> NoMethodError: undefined method `[]='

Ruby evaluates neither the right hand side, nor the argument, i.e.

nil[foo]=bar

doesn't raise a NameError, although foo and bar are undefined.

The expression seems to be equivalent to nil:

$ ruby --dump=insns -e 'nil[foo]=bar'
== disasm: #<ISeq:<main>@-e>============================================
0000 trace            1                                               (   1)
0002 putnil
0003 leave

$ ruby --dump=insns -e 'nil'
== disasm: #<ISeq:<main>@-e>============================================
0000 trace            1                                               (   1)
0002 putnil
0003 leave
Proudman answered 27/4, 2016 at 16:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.