aero6dof
9/4/2003 6:39:00 AM
"Mark J. Reed" <markjreed@mail.com> 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;
}