[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: show me the ruby way

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;
}
4 Answers

Mark J. Reed

9/4/2003 3:00:00 PM

0

On Wed, Sep 03, 2003 at 11:38:40PM -0700, Alan Chen wrote:
> > 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.

It already behaves perfectly consistently. The return value of the
block is what is returned when the key is not present. That''s it,
that''s all, nothing more, nothing less. I completely fail to see the
problem. It''s not an "edge case". You''re looking for extra magic
that is neither called for nor even desirable.

If you want the block to both set and return the hash value, just do it as
the last statement in the block.

There are a myriad of other cases where you can do weird things to
the receiver inside a block and thereby get what appears to be inconsistent
behavior from the outside. That''s a feature, not a flaw; Ruby doesn''t
try to protect programmers from themselves invasively.

-Mark

Aria Stewart

9/4/2003 4:10:00 PM

0

> # 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.

Good use I can think of:

hb3 = Hash.new { |h,k|
Thread.new {
some_task_with_immense_processing_that_assigns_to_h(h, k)
}
"incomplete"
}

I can see that being used in the app I''m writing -- a clone of
Rhythmbox, which is a clone of iTunes -- I''d use it in the music-library
classes, where scanning the disk for music can take tens of minutes, but
the GUI is in it''s own thread...

In writing this, I''m trying to outperform Rhythmbox 0.5 (which is coded
in C) in Ruby, just because an agile language lets you tune the
algorithms more easily.

Ari


aero6dof

9/4/2003 10:58:00 PM

0

Since it''s clear that I''m out of sync with everybody else on this
issue, I''ll stop the torture and drop it :). However, Ari, you will
want to be careful with the construct you orignally posted. If your
GUI allows the user to cause an access the same undefined key before
the thread completes, you''ll kick off redundant threads searching
for the same resource.

Aredridel <aredridel@nbtsc.org> wrote in message news:<1062691741.4672.4.camel@mizar.nbtsc.org>...
> hb3 = Hash.new { |h,k|
h[k] = "incomplete" #ADDED: define the value for the key
> Thread.new {
> some_task_with_immense_processing_that_assigns_to_h(h, k)
> }
> "incomplete"
> }

Ari,

Hal E. Fulton

9/5/2003 2:46:00 AM

0

Aredridel wrote:
> Good use I can think of:
>
> hb3 = Hash.new { |h,k|
> Thread.new {
> some_task_with_immense_processing_that_assigns_to_h(h, k)
> }
> "incomplete"
> }
>
> I can see that being used in the app I''m writing -- a clone of
> Rhythmbox, which is a clone of iTunes -- I''d use it in the music-library
> classes, where scanning the disk for music can take tens of minutes, but
> the GUI is in it''s own thread...

I find this to be very clever. I''d want it to be
commented, though, if I were reading the code. :)

This snippet should perhaps be captured somewhere.

Hal