On 8/12/06, Robert Klemme <shortcutter / googlemail.com> wrote:
> x1 wrote:
> > Yep.. Thanks alot. This some pretty neat stuff. :-)
> >
> > hash = {
> >     "foo" => Proc.new {
> >          x = []
> >          y = []
> >          hash = {
> >               "x" => ["a", "b", "c"].each {|i| x << i},
> >               "y" => ["x", "y", "z"].each {|i| y << i}
> >          }
> >     }.call
> > }
> > puts hash['foo']["y"][1]
> > puts hash['foo']["x"][1]
> >
> >> ruby test1.rb
> > y
> > b
> >> Exit code: 0
>
> This code looks completely useless to me.  You end up with the same hash
> whatever you do since there is no parametrization to your code.  Where
> is the point?  Did I miss something?

I'm in agreement!

That complicated expression produces exactly the same results as

hash = { "foo" => {"x" => %w{a b c}, "y" => %w{x y z}}}

For the newbies, note that %w{a b c} is an array literal equivalent to
["a", "b", "c"] but more sparing on the fingers pushing the keys.

And

x = []
%w{a b c}.each { | i | x << i }

is equivalent to
%w{a b c}.each { | i | i}

except for the side effect of appending all the elements to x, which
is then discarded anyway.

AND that last expression is equivalent to:
%w{a b c}

ALSO note that each actually returns the receiver of each,  the block
might have side effects, but it normally doesn't affect the result:

ar =  %w{a b c}
ar.each{ | i | i + "X"} => ["a", "b", "c"]

There's also a potential problem here because of object identity.

ar.equal?( ar.each{ | i | i}) => true

So the result of each is the same object, with the same object_id.
This probably isn't a problem here because the literal in the original
expression isn't referenced anywhere else.  There cases in ruby where
unknowingly having two references to the same object can cause
suprising results when a change to the object made through one
reference can show up in other references:

a = b = %w{a b c}

a => ["a", "b", "c"]
b => ["a", "b", "c"]

a[1] = 'q'
a => ["a", "q", "c"]
b => ["a", "q", "c"]

To have the result be based on the values of the block you need to use
another method from enumerable such as map

ar.map{ | i | i} => ["a", "b", "c"]

which produces a new array with a different identity.

ar.equal?( ar.map{ | i | i}) => false

But since we are using a block which is an identity transformation
here, a much clearer way to do this is to simply duplicate the array

ar.dup  => ["a", "b", "c"]
ar.equal?(ar.dup) => false

-- 
Rick DeNatale

http://talklikeaduck.denhaven2.com/