From: Josh Cheek Date: 2011-02-23T16:43:58+09:00 Subject: Re: Ruby Hash Keys and Related Questions --20cf3054a34dc01fe5049cee410c Content-Type: text/plain; charset=ISO-8859-1 On Wed, Feb 23, 2011 at 12:42 AM, Terry Michaels wrote: > I'm still a bit new to Ruby, so humor me a bit. But I discovered today > (through trial and error) that not only can Strings, numbers, and > symbols be keys for hashes, but also any object, or even a class name! > Ruby is the first language I've used in which I would have even thought > to try that, let alone it actually working: > > > irb(main):001:0> hsh = {} > => {} > irb(main):002:0> obj = Object.new > => # > irb(main):003:0> obj2 = Object.new > => # > irb(main):004:0> hsh[obj] = "blah" > => "blah" > irb(main):005:0> hsh[obj2] = "ble" > => "ble" > irb(main):006:0> puts hsh[obj2] > ble > => nil > irb(main):007:0> puts hsh[obj1] > NameError: undefined local variable or method `obj1' for main:Object > from (irb):7 > irb(main):008:0> puts hsh[obj] > blah > => nil > irb(main):009:0> clone = obj > => # > irb(main):010:0> puts hsh[clone] > blah > => nil > irb(main):011:0> class Cl > irb(main):012:1> end > => nil > irb(main):013:0> hsh[Cl] = "blo" > => "blo" > irb(main):014:0> puts hsh[obj] > blah > => nil > irb(main):015:0> puts hsh[Cl] > blo > => nil > irb(main):016:0> class Cl2 > irb(main):017:1> end > => nil > irb(main):018:0> hsh[Cl2] = "blu" > => "blu" > irb(main):019:0> puts hsh[Cl] > blo > => nil > irb(main):020:0> puts hsh[Cl2] > blu > > Anyway, this raised a few related questions in my mind: > > 1. If the "key" taken by hash[key]= can be any object, and the key still > works even after it is aliased to another variable, does that mean that > the "key" is just a reference? > > The key can be any object that implements the methods "hash" and "eql?" I'm not sure what you mean when you say "does that mean the 'key' is just a reference?" If you are asking what Ruby is passing around, the answer is "a pointer to the object". That is less interesting in this case, the more interesting thing is why it is behaving that way, which is that objects have hash defined on them, which returns their object_id o = Object.new o.hash # => 2154796 o.object_id # => 2154796 I don't know if you know how hashes are implemented, but internally they map objects to array indexes. The way Ruby does this is with the hash method, which returns a number that correlates to the index. In your example with obj and obj2, you can store different values there. But they are both just empty objects, does it make sense to consider them two different keys or the same key? With objects like this, they get different keys because they will have different object ids. But think about a String, where each string is different. a1 = 'a' a2 = 'a' a1.object_id # => 2153018 a2.object_id # => 2153004 Do you want to have to always keep track of which string you used as the key? No. So the hash for a string is based on the string value, in this case "a", rather than the specific instance of "a" that was used to put it into the hash. a1.hash # => 14815807 a2.hash # => 14815807 2. If I pass in a number, say an Integer, as a key, does Ruby actually > use the Integer? Or does it use a reference to an Integer object? > (Numbers are objects too, right?) > > There have been long discussions about this, Caleb Clousen tells me that Fixnums are copied every time they are passed as an argument. He has gone much deeper than I have, so presumably he knows what he is talking about, but Ruby goes to really great lengths to hide this from you, to the point that you must construct contrived explanations to handle the contradictions that such models have. I think it is best to Just consider every variable a pointer to the object. Fixnum or not. > 3. If I am allowed to pass in a class as a key, does that mean that > classes are objects too? If not, what exactly is being stored as the > key? > > Yes, classes are objects: class C end c = C c == C # => true C.class # => Class C.object_id # => 2156420 C.hash # => 2156420 classes = [C,Array,String] classes # => [C, Array, String] Notice that they inherit the default hash method that just uses their object id as the hash key. > 4. When I use irb, and a line returns an object, irb shows me the > object's hexadecimal reference address (or at least, that's what it > looks like). Is there a method one can call on an object to get that > reference when one is not in irb? Just curious. > > object.object_id ----- If you're interested, here is about as simple of an implementation of a hash table as you can get https://gist.github.com/840135 The purpose is to conceptually understand that hashes internally use arrays, and see a simple example of how they achieve this. Real hashes are much more complex (ie what happens if two objects hash to the same value? what happens if two different objects should be considered the same hash key? what happens when the array gets full? how is the #hash method written? etc.) --20cf3054a34dc01fe5049cee410c--