Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

i'm using Ruby 1.9.3

I figured out that you can use an array, or a hash as hash key in ruby:

h = Hash.new

h[Array.new] = "Why?"
h[Array.new] # Output: "Why?"

h[Hash.new] = "It doesn't make sense"
h[Hash.new] # Output: "It doesn't make sense"

But an object works differently...

h[Object.new] = "LOL"
h[Object.new] # Output: "nil"

But this one works as expected:

o = Object.new

h[o] = "LMAO"
h[o] # Output: "LMAO"

Tried this:

o = Object.new           # Output: #<Object:0x2c78c10>
h["#<Object:0x2c78c10>"] # Output: nil

Tried it in Python and PHP and it throws an error.

I'm just curious about how it works, and why would you want to use an array, or a hash as hash key in ruby?

Thanks.

share|improve this question
add comment

3 Answers

up vote 3 down vote accepted

Why wouldn't you? You can use any object as a Hash key in Ruby. (Well, any object that responds to hash and eql?, but since there are definitions of those in Object, that's pretty much all objects.) It would be strange and inconsistent if you would arbitrarily exclude two classes from that.

share|improve this answer
add comment

Well, you probably know this much already; but for starters, I'd say that's probably very bad practice. Still, it's an interesting functionality question, so I'll give it a shot...

From what I understand, Ruby maintains its empty arrays and hashes all as one singleton object, just as Nil is a single object in the entire program. If you declare 5 arrays with nothing in them, they're all the same reference - just like if you made 5 similar strings in C#, Javascript (and if I remember right, Ruby). They likely become seperate instances once values are added to them.

However, there are valid reasons to maintain Object.new's as seperate instances - the most common use I would know of is as multithreading tokens; times when you want to maintain something by hash map, but since it's so code-internal, a string isn't the most logical key.

The root of my answer, as I understand it, is that those classes work in kinda-exceptional ways within the language that you may not see with other types. I haven't used Ruby in a while, so I may need to get this verified by others.

share|improve this answer
    
So maybe arrays and hashes in Ruby are lazy loaded? –  random_guy May 13 '13 at 21:23
1  
The reason that Object.new when called as a key doesn't match is because it is a new Object. It did not exist until you called it when you were trying to retrieve the key. This makes perfect sense, as you show when you store that new Object and then query the Hash for that value. –  vgoff May 13 '13 at 22:06
    
The reason why they behave differently, is because they override hash and sql?, not because of some magical singleton object pooling caching thingy. I don't know of any Ruby implementation that does something even remotely similar to what you describe, and if there were, that would be a private internal implementation optimization detail that would not be allowed to change user-visible behavior. –  Jörg W Mittag May 13 '13 at 22:37
add comment

Why limit the keys by a limited set of types? As long as it is an Object, you can use it as a key. Even a Proc or lambda can be used.

my_proc = Proc.new { "Hello World #{Time.now}!"}
my_hash = { my_proc => 'a proc', my_proc.call => "a proc that was called at #{Time.now}" , [3, 2, 1] => 'My 3, 2, 1 array'}
my_hash.default = "There is no key with this value"
puts my_hash[my_proc]
puts my_hash[my_proc.call].inspect
sleep(1)
puts my_hash[my_proc.call].inspect
puts my_hash[[3, 1, 2].sort.reverse]
puts my_hash
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.