user428517
user428517

Reputation: 4193

Ruby: setting a new hash with an array of keys/values

I'm learning Ruby via RubyMonk. In the solution to the waiter robot problem, there's a line of code that creates a new hash using an array:

o = Hash[*order]

given

order = [:table, 1, :sandwich, "denver", :drink, "mango shake"]

I understand what's being done here and how the splat operator works. However, I'm confused about the syntax for creating this hash. RubyDoc says that ::[] is really the method being called, so I was able to determine that o = Hash::[](*order) is the same thing. But why can this be shortened to just Hash[*order]? Is this a special construct that gets interpreted by the parser, or is there another reason? Along the same lines, why don't any of the following work?

o = Hash.new
o.[](*order)

or

o = Hash.new
o[*order]

or even something like o = {}[*order]

I know these shouldn't work; I'm just not sure why. I think I'm confused by the usage of Hash[*order] without first instantiating a hash with Hash.new. Is this an example of the difference between class methods and instance methods?

(As a side note, it seems to me that o = {*order} should work, but it doesn't.)

Can someone explain what's going on here, and if there are alternate ways to add values from an array into a hash?

Upvotes: 4

Views: 471

Answers (2)

mattr-
mattr-

Reputation: 5821

When you write Hash(*order) you're actually calling the Hash method in the Kernel module, which is not the same as calling the [] method in the Hash class. See the docs for Kernel#Hash to see what's going on under the hood there.

Upvotes: 1

Darshan Rivka Whittle
Darshan Rivka Whittle

Reputation: 34031

Is this an example of the difference between class methods and instance methods?

Exactly.

But why can this be shortened to just Hash[*order]?

Ruby interprets some_object[] as a call to the method named [] on some_object. This isn't special for Hashes, you can implement a [] method in any class of your own and use that syntax.

Can someone explain what's going on here, and if there are alternate ways to add values from an array into a hash?

Hash[*order] calls a class method (Hash#[]) which creates a new Hash. o.[](*order) doesn't work for the same reason you can't call new on it: {}.new doesn't make any sense. You can't call a class method on an instance of the class.

You can add values with merge:

o = Hash.new
o.merge(Hash[*order])

o = {*order} doesn't work because {} is the syntax for a Hash literal, and putting *order in there doesn't make sense.

Hash(*order) is Kernel#Hash, a method that expects only one argument.

Upvotes: 3

Related Questions