being very confused about this hash

R

Ruby Newbee

Hi,

irb(main):039:0> hash = Hash.new []
=> {}
irb(main):040:0> hash['abc'] << 3
=> [3]
irb(main):041:0> hash.keys
=> []
irb(main):042:0> hash['def']
=> [3]


Since I have created a key/value pair with hash['abc'] << 3, why
hash.keys show nothing?
And, why hash['abc'] << 3 changed the hash's default value (which
should be an empty array)?

Thanks.
 
B

Bill Kelly

Ruby said:
irb(main):039:0> hash = Hash.new []
=> {}
irb(main):040:0> hash['abc'] << 3
=> [3]
irb(main):041:0> hash.keys
=> []
irb(main):042:0> hash['def']
=> [3]


Since I have created a key/value pair with hash['abc'] << 3, why
hash.keys show nothing?
And, why hash['abc'] << 3 changed the hash's default value (which
should be an empty array)?

I'm not sure why hash.keys was empty.

But with regard to the default value, we are providing an
object (a specific instance of the Array class) to be used
as the default.

We can illustrate this by asking Ruby to show us the object_id
of the default object:

irb(main):001:0> ary = []
=> []
irb(main):002:0> ary.object_id
=> 20919800
irb(main):003:0> h = Hash.new ary
=> {}
irb(main):004:0> h['foo'].object_id
=> 20919800
irb(main):005:0> h['bar'].object_id
=> 20919800

So we can see the object_id of the default object is indeed
the same object_id of the array we provided to Hash.new.

* * *

We can instead provide a block to Hash.new which allows us
to create a _new_ unique object (instance of Array) whenever
a new default value is needed:

irb(main):001:0> h = Hash.new {|h,k| h[k] = []}
=> {}
irb(main):002:0> h['abc'] << 3
=> [3]
irb(main):003:0> h.keys
=> ["abc"]
irb(main):004:0> h['def']
=> []


Regards,

Bill
 
D

David Masover

irb(main):039:0> hash = Hash.new []

I assume here that [] is the default value, right?
=> {}
irb(main):040:0> hash['abc'] << 3
=> [3]
irb(main):041:0> hash.keys
=> []
irb(main):042:0> hash['def']
=> [3]


Since I have created a key/value pair with hash['abc'] << 3, why
hash.keys show nothing?

Because you haven't set anything in the hash. That is,

hash['abc'] = 3

is equivalent to:

hash.[]=('abc', 3)

On the other hand, what you've done is:

hash['abc'] << 3

That's equivalent to:

hash.[]('abc') << 3

I don't know if that helps, but that's the difference. Let me put it this way
-- suppose you hadn't changed the default value:

irb(main):001:0> hash = {}
=> {}
irb(main):002:0> hash['abc']
=> nil
irb(main):003:0> hash.keys
=> []

Do you understand why that works the way it does? But there's nothing special
about nil here, it's just the, erm, _default_ default value -- it's what Hash
uses as a default value if you don't specify one.
And, why hash['abc'] << 3 changed the hash's default value (which
should be an empty array)?

Because you set the default value to [], which creates an empty array object,
once. The hash is just assigning it each time. Think of it this way:

irb(main):004:0> default = []
=> []
irb(main):005:0> a = default
=> []
irb(main):006:0> b = default
=> []
irb(main):007:0> a << 3
=> [3]
irb(main):008:0> b
=> [3]

What you really want is the block notation of creating a hash, which lets you
actually specify some code that's run to create a default value, as Bill Kelly
says. The reason his code works is that when you try to access a value that
doesn't exist, it actually runs some code which sets that value:

h = Hash.new {|h,k| h[k] = []}

It wouldn't work at all if you just did this:

h = Hash.new {|h,k| []}

That would at least give you a new array each time, but since it wouldn't set
it, you'd see weird things:

irb(main):010:0> h['abc'] << 3
=> [3]
irb(main):011:0> h['abc']
=> []
irb(main):012:0> h.keys
=> []
 
R

Ruby Newbee

Since I have created a key/value pair with hash['abc'] << 3, why
hash.keys show nothing?

Because you haven't set anything in the hash. That is,

hash['abc'] = 3

is equivalent to:

hash.[]=('abc', 3)

On the other hand, what you've done is:

hash['abc'] << 3

That's equivalent to:

hash.[]('abc') << 3


Thanks for the explaining, now I think I have got it.
I'm always thinking it as the Perl way, since in Perl the syntax like
hash['abc'] << 3 will create a key/value pairs.

perl -MData::Dumper -le '$hash={}; push @{$hash->{'abc'}},3; print Dumper $hash'
$VAR1 = {
'abc' => [
3
]
};


I didn't know in Ruby hash['abc'] = 3 and hash['abc'] << 3 are different.
Thanks again.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Is this how you start a hash? 6
Hash keys don't work as expected 10
nested def's 6
What does this hash do? Is this a hash? 3
Problem with hash (again) 8
hash example 2
Dealing with nil 5
Threads & GC 2

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top