2007/9/3 said:
Hi --
Can someone explain why there is a difference in the second line of
output for the two hashes:
h = Hash.new(5)
puts h[2]
h[2] ||= 10
p h
#----------
puts
#----------
h = Hash.new
puts h[2]
h[2] ||= 10
p h
---output:--
5
{}
nil
{2=>10}
x ||= y is, I think, always supposed to be exactly equivalent to
x = x || y, so that line in your first hash should be equivalent to:
h[2] = 5 || 10
which should assign 5 to h[2]. It looks to me like you've found a bug.
I can't think of any reason (and I really hope there isn't one,
because having an exception to that ||= rule would be very messy) why
using a default hash value would make any difference here. It's still
5 || 10 on the rhs, and it's still just an assignment.
I can't point my finger on it but I believe x||=y is equivalent to
"x=y unless x" instead of "x=x||y". It seems to be more reasonable to
skip the assignment altogether if the value is true equivalent
already. That would also explain behavior much better.
Note also:
$ ruby -e 'h=Hash.new 2;set_trace_func lambda {|*a| p a}; h[4]||=10'
["line", "-e", 1, nil, #<Binding:0x1002ff48>, false]
["c-call", "-e", 1, :[], #<Binding:0x1002ff0c>, Hash]
["c-call", "-e", 1, :default, #<Binding:0x1002fdf4>, Hash]
["c-return", "-e", 1, :default, #<Binding:0x1002fcf0>, Hash]
["c-return", "-e", 1, :[], #<Binding:0x1002fc00>, Hash]
$ ruby -e 'h=Hash.new 2;set_trace_func lambda {|*a| p a}; h[4]=h[4]||10'
["line", "-e", 1, nil, #<Binding:0x1002fee4>, false]
["c-call", "-e", 1, :[], #<Binding:0x1002fea8>, Hash]
["c-call", "-e", 1, :default, #<Binding:0x1002fd90>, Hash]
["c-return", "-e", 1, :default, #<Binding:0x1002fc8c>, Hash]
["c-return", "-e", 1, :[], #<Binding:0x1002fb9c>, Hash]
["c-call", "-e", 1, :[]=, #<Binding:0x1002faac>, Hash]
["c-return", "-e", 1, :[]=, #<Binding:0x1002f9bc>, Hash]
There is no assignment in the first piece.
Kind regards
robert