From: aero6dof@... (Alan Chen) Date: 2003-09-04T15:45:00+09:00 Subject: Re: show me the ruby way "Mark J. Reed" wrote in message news:<20030903185333.GA19685@mulan.thereeds.org>... > .... hash logic snipped Thanks for taking to time to explain the hash logic, but as I mentioned at the start, I already understand the current implementation. Primarily, I'm interested in the edge case. > Having the block modify the hash is a side effect. Having the block > modify the hash AND return a different value than the one it > stores is just plain weird, and if you do it you deserve whatever you > get. :) Currently thats correct, but this patch makes the hash default block logic behave more consistently. I think it preserves all of the intentional logic of the current hash default block while fixing up the odd edge case that I've been so poorly explaining my interest in. :) As far as I've accounted for those cases are as follows: # case 0 h = Hash.new h[undefinedkey] == nil # case 1 ho = Hash.new(object) ho[undefinedkey] == object # case 2 hb1 = Hash.new { |h,k| h[k] = defaultvalue } hb1[undefinedkey] == defaultvalue # case 3 hb2 = Hash.new { |h,k| # ... any logic but setting h[k] defaultvalue } hb2[undefinedkey] == defaultvalue # case 4 hb3 = Hash.new { |h,k| h[k] = defaultvalue # ... side calc } # current behavior hb3[undefinedkey] == side calc result on first access hb3[nowdefinedkey] == defaultvalue (on accesses after the default block has run) # behavior with patch hb3[undefinedkey] == defaultvalue My question regarding intent was to find out if anybody depended on, expected, or liked the current behavior in case 4. I obviously dislike having behavior where a hash value can appear to be one value in the initial access with an undefined key and another value on subsequent accesses after the default key has defined the value. Now the price you pay to get case 4 to work in the patch is the additional st_lookup call in cases 2,3, and 4. --- hash.c.orig 2003-09-03 23:03:24.000000000 -0700 +++ hash.c 2003-09-03 23:08:10.000000000 -0700 @@ -329,7 +329,14 @@ rb_scan_args(argc, argv, "01", &key); if (FL_TEST(hash, HASH_PROC_DEFAULT)) { - return rb_funcall(RHASH(hash)->ifnone, id_call, 2, hash, key); + VALUE val; + VALUE procres = rb_funcall(RHASH(hash)->ifnone, id_call, 2, hash, key); + if (st_lookup(RHASH(hash)->tbl, key, &val)) { + return val; + } + else { + return procres; + } } return RHASH(hash)->ifnone; }