>From Facets' multiton.rb (which is primarily Floran Franks' work), I'm
getting somthing that doesn't make any sense:
POOLS[self] ||= {}
p POOLS[self].class
p POOLS[self].keys
Is outputing:
Hash
[[{:strip_comments=>false}], [{:strip_comments=>false}]]
How can two identical keys be in a hash?
T.
on 26.12.2006 18:50
on 26.12.2006 19:16
On 12/26/06, Trans <transfire@gmail.com> wrote: > [[{:strip_comments=>false}], [{:strip_comments=>false}]] > > How can two identical keys be in a hash? > > T. > irb(main):005:0> bob = [{:whee => false}] => [{:whee=>false}] irb(main):006:0> bob.hash => 23244868 irb(main):007:0> roger = [{:whee => false}] => [{:whee=>false}] irb(main):008:0> roger.hash => 23235888 irb(main):009:0> bob.eql? roger => false irb(main):010:0> bob[0].eql? roger[0] => false irb(main):011:0> bob[0].hash => 23244870 irb(main):012:0> roger[0].hash => 23235890 I think it boils down to: there is no Hash#hash which inspects the contents - Hash inherits Object#hash which is Object#object_id, and the two hashes, while they appear to have the same contents, are not the same object. So the keys are not "identical". -A
on 26.12.2006 19:20
Looks to me that your keys are arrays. My guess is that p POOLS[self].keys[0].class will return Array, instead of Symbol, which is what you're probably expecting. So, the hash doesn't have identical keys. It has two different keys, each of which is a different array with identical members. Try p POOLS[self].keys[0].object_id p POOLS[self].keys[1].object_id and you'll see the keys really are different.
on 26.12.2006 20:06
thanks Ara and Jon,
I see what your saying. I was using #== not #eql? in comparing the
keys. So I see why it's faling now. How do I get aorund this? I'm
caching object based on therr initialization paramaters, which has to
be an array. Is there a simpler way or do I have to do something like:
class Parameters < Array
alias :eql? :==
end
T.
on 26.12.2006 20:24
Trans wrote: > thanks Ara and Jon, > > I see what your saying. I was using #== not #eql? in comparing the > keys. So I see why it's faling now. How do I get aorund this? I'm > caching object based on therr initialization paramaters, which has to > be an array. Is there a simpler way or do I have to do something like: > > class Parameters < Array > alias :eql? :== > end Ugh. Nothing like that works either. It's not using eql? or equal?, but rather #hash (I guess that's actually what you were trying to say Ara). This doen't make any sense to me. Why do identical strings and arrays have the same #hash value but not hashes? T.
on 26.12.2006 20:40
Trans wrote: > > T. How about association lists? irb(main):029:0> a1=[[:strip,false]] => [[:strip, false]] irb(main):030:0> a2=[[:strip,false]] => [[:strip, false]] irb(main):031:0> h={} => {} irb(main):032:0> h[a1] = 'foo' => "foo" irb(main):033:0> h[a2] = 'bar' => "bar" irb(main):034:0> h => {[[:strip, false]]=>"bar"}
on 26.12.2006 20:54
On Dec 26, 2006, at 11:22, Trans wrote: >> alias :eql? :== >> end > > Ugh. Nothing like that works either. It's not using eql? or equal?, > but > rather #hash (I guess that's actually what you were trying to say > Ara). A Hash only asks if one object is #eql? to another when they have the same #hash. You can't use a Hash as a Hash key because Hash#hash is not implemented that way. > This doen't make any sense to me. Why do identical strings and arrays > have the same #hash value but not hashes? Likely because: s = '' s.hash and: a = [] a << a a.hash are easier to compute than: h = {} h[h] = h h.hash -- Eric Hodel - drbrain@segment7.net - http://blog.segment7.net I LIT YOUR GEM ON FIRE!
on 26.12.2006 20:58
Trans wrote: > > end > > Ugh. Nothing like that works either. It's not using eql? or equal?, but > rather #hash (I guess that's actually what you were trying to say Ara). > This doen't make any sense to me. Why do identical strings and arrays > have the same #hash value but not hashes? Nope. It doesn't even use #hash. So it must be using #object_id with an exception for Strings and Arrays. Dissapointing to say the least. I had to resort to recursively converting all hashes to arrays. T.
on 26.12.2006 21:10
Eric Hodel wrote: > >> class Parameters < Array > not implemented that way. I see. So it's not using object_id but a.hash == b.hash && a.eql?(b) Is that right? > a = [] > a << a > a.hash > > are easier to compute than: > > h = {} > h[h] = h > h.hash Hmm... the expection gums up the works. T.
on 26.12.2006 21:14
William James wrote: > > end > > > > T. > > How about association lists? Thanks William! That's what I did and worked (desipite inefficency). T.
on 26.12.2006 21:16
Trans wrote:
> thanks Ara and Jon,
Oops. Just saw that was Alex, not Ara, sorry about that Alex! And
thanks for the help.
T.
on 26.12.2006 21:46
On Wed, 27 Dec 2006, Trans wrote: > [[{:strip_comments=>false}], [{:strip_comments=>false}]] > > How can two identical keys be in a hash? > > T. hi trans- afaik multiton.rb is mine http://codeforpeople.com/lib/ruby/multiton/multiton-1.0.2/lib/multiton.rb the logic behind POOLS is that objects are cached this way POOLS[ class_of_object ][ args_given_to_new ] = obj in otherwords, contructing two objects with the same argument lists will contruct only one object. it's the argument lists which are used to determine uniqueness. alternatively uniqueness will be determined via the method 'multiton_id' if you're class has implimented that instance method or the object in question responds to it otherwise. so, in your case, you might use something like hash.to_a.sort.hash or something unique like that. eg class MyClass include Multiton attr :multiton_id def initialize h = {} @multiton_id = h.to_a.sort.hash super end end kind regards. -a
on 26.12.2006 23:06
Trans wrote: > > > alias :eql? :== > > > end > > > > > > T. > > > > How about association lists? > > Thanks William! That's what I did and worked (desipite inefficency). > > T. Here's a speed comparison for various numbers of keys: require 'benchmark' $iterations = 40_000 def rand_sym letters = ('a'..'z').to_a sym = "" 8.times{ sym << letters[ rand(letters.size) ] } sym.to_sym end def test_assoc n alist = [] keys = [] while alist.size < n do key = rand_sym unless keys.include?( key ) alist << [ key, true ] keys << key end end $iterations.times{ keys.each{|key| fail if alist.assoc(key)[1] != true } } end def test_hash n hash = {} keys = [] while hash.size < n key = rand_sym unless hash.include?( key ) hash[key] = true keys << key end end $iterations.times{ keys.each{|key| fail if hash[key] != true } } end Benchmark.bm(8) do |x| [1,2,3,7,20].each{ |n| x.report("assoc %2d" % n) { test_assoc n } x.report("hash %2d" % n) { test_hash n } } end user system total real assoc 1 0.150000 0.000000 0.150000 ( 0.171000) hash 1 0.130000 0.000000 0.130000 ( 0.140000) assoc 2 0.291000 0.000000 0.291000 ( 0.310000) hash 2 0.200000 0.000000 0.200000 ( 0.231000) assoc 3 0.440000 0.000000 0.440000 ( 0.460000) hash 3 0.291000 0.000000 0.291000 ( 0.311000) assoc 7 1.172000 0.000000 1.172000 ( 1.252000) hash 7 0.590000 0.000000 0.590000 ( 0.640000) assoc 20 5.188000 0.000000 5.188000 ( 5.578000) hash 20 1.652000 0.000000 1.652000 ( 1.813000)
on 27.12.2006 00:34
William James wrote: > sym.to_sym > end > key = rand_sym > Benchmark.bm(8) do |x| > hash 2 0.200000 0.000000 0.200000 ( 0.231000) > assoc 3 0.440000 0.000000 0.440000 ( 0.460000) > hash 3 0.291000 0.000000 0.291000 ( 0.311000) > assoc 7 1.172000 0.000000 1.172000 ( 1.252000) > hash 7 0.590000 0.000000 0.590000 ( 0.640000) > assoc 20 5.188000 0.000000 5.188000 ( 5.578000) > hash 20 1.652000 0.000000 1.652000 ( 1.813000) Nice. Doesn't matter a whole lot a few keys but there is a clear slow down. I came up with another possibility however. I won;t work for all cases, but using Marshal.dup on the args instead of converting to assoc gives the proper result too. Wonder how that would benchmark? T.
on 27.12.2006 00:38
ara.t.howard@noaa.gov wrote: > > > > http://codeforpeople.com/lib/ruby/multiton/multiton-1.0.2/lib/multiton.rb Somehow I got Florian Franks name attached to that. Well, unless Florian's got something to say about it, I'll reattribute to you. Sorry about that! T.