Hash.new(Hash.new) doesn't use Hash.new as default value 
Author Message
 Hash.new(Hash.new) doesn't use Hash.new as default value

Hi -

In the documentation for the 'new' method in the Hash class in Programming
Ruby it says that 'anObject' will be used as default value, but consider the
following example:

var = Hash.new(Hash.new)
var['index1'] = 'value1'
var['index2']['index22'] = 'value22'
var['index3']['index32'] = 'value32'
var['index4'] = 'value4'
p var['donotexist']

Why does "p var['donotexist']" output {"index32" => "value32", "index22" =>
"value22"} - and _not_ just {} (a new Hash)?
If it's no bug, I think it's a bug in documentation. - and not a very logic
behavior.

--
Mvh./Best Regards
Jonas Delfs, http://www.*-*-*.com/



Sun, 12 Sep 2004 22:00:08 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

J> If it's no bug, I think it's a bug in documentation. - and not a very logic
J> behavior.

 No, it's not a bug nor a bug in the documentation.

 What you must understand is that when you write

  Hash.new(Hash.new)

 is like

  default_value = Hash.new
  Hash.new(default_value)

 i.e. default_value is used each times a key is not defined

 When you write

 var['index2']['index22'] = 'value22'

 because var['index2'] is not defined, ruby will do something like this

  var['index2'] = default_value
  default_value['index22'] = 'value22'

 Same with

  var['index3']['index32'] = 'value32'

 it do

  var['index3'] = default_value
  default_value['index32'] = 'value32'

 When you ask for var['donotexist'] it give you the variable default_value,
 i.e. the hash {"index32" => "value32", "index22" =>"value22"}

 With 1.7 you'll have the possibility to write

 Hash.new { Hash.new }

 and each times a key is not defined, ruby will evaluate the block, the
 result of the block will be stored in the Hash and ruby will do what you
 want.

Guy Decoux



Sun, 12 Sep 2004 22:22:02 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Quote:

> In the documentation for the 'new' method in the Hash class in Programming
> Ruby it says that 'anObject' will be used as default value, but consider the
> following example:

> var = Hash.new(Hash.new)
> var['index1'] = 'value1'
> var['index2']['index22'] = 'value22'
> var['index3']['index32'] = 'value32'
> var['index4'] = 'value4'
> p var['donotexist']

> Why does "p var['donotexist']" output {"index32" => "value32", "index22" =>
> "value22"} - and _not_ just {} (a new Hash)?
> If it's no bug, I think it's a bug in documentation. - and not a very logic
> behavior.

The default value is the hash created by Hash.new. There's just one of
these, which is the default value for all entries. As a result,
var['index2], var['index3'], and val['dontexist'] share it, which is
the effect you're seeing.

Dave



Sun, 12 Sep 2004 22:27:33 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value


Quote:

> J> If it's no bug, I think it's a bug in documentation. - and not a very
logic
> J> behavior.

>  No, it's not a bug nor a bug in the documentation.

>  What you must understand is that when you write

>   Hash.new(Hash.new)

>  is like

>   default_value = Hash.new
>   Hash.new(default_value)

Ohh. I think it's the fact that everything by default gets passed by
reference that have tricked me.
I can't force Ruby to .dup that object, can I?

Quote:
>  With 1.7 you'll have the possibility to write

>  Hash.new { Hash.new }

>  and each times a key is not defined, ruby will evaluate the block, the
>  result of the block will be stored in the Hash and ruby will do what you
>  want.

Okay.

--
Mvh./Best Regards
Jonas Delfs, http://delfs.dk



Sun, 12 Sep 2004 22:38:45 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

J> I can't force Ruby to .dup that object, can I?

 Actually you can't if you use this syntax.

 You have a module

  http://www.ruby-lang.org/en/raa-list.rhtml?name=PerlValue

 which do something similar to a P language

Guy Decoux



Sun, 12 Sep 2004 23:10:49 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value
Hi,

In message "Re: Hash.new(Hash.new) doesn't use Hash.new as default value"

| With 1.7 you'll have the possibility to write
|
| Hash.new { Hash.new }
|
| and each times a key is not defined, ruby will evaluate the block, the
| result of the block will be stored in the Hash and ruby will do what you
| want.

It does not store the evaluated default value.  Should it?

                                                        matz.



Sun, 12 Sep 2004 23:16:19 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Y> It does not store the evaluated default value.

 Yes, you are right. Sorry for the misinformation

Y>  Should it?

 It depend if you want that it work like a P language (not really a good
 reference for me :-)))

Guy Decoux



Sun, 12 Sep 2004 23:27:09 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value


Quote:
> In message "Re: Hash.new(Hash.new) doesn't use Hash.new as default value"

> | With 1.7 you'll have the possibility to write
> |
> | Hash.new { Hash.new }
> |
> | and each times a key is not defined, ruby will evaluate the block, the
> | result of the block will be stored in the Hash and ruby will do what you
> | want.

> It does not store the evaluated default value.  Should it?

If not it will not be possible to do
var['index']['anotherIndex'] = 'value'
without having defined var['index'] to be a Hash first, so in this case:
yes.
But, I can also think of situations where it would be very unhandy if an
index gets a value just by accessing it.

Maybe we can provide an optional argument to 'new'?

--
Mvh./Best Regards
Jonas Delfs, http://delfs.dk



Sun, 12 Sep 2004 23:30:03 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Quote:



> > It does not store the evaluated default value.  Should it?

> If not it will not be possible to do var['index']['anotherIndex'] =
> 'value' without having defined var['index'] to be a Hash first, so
> in this case: yes.  But, I can also think of situations where it
> would be very unhandy if an index gets a value just by accessing it.

> Maybe we can provide an optional argument to 'new'?

Perhaps the distinction is whether it's being used as an lvalue or an
rvalue. As an lvalue, it should be stored, but as an rvalue it
probably shouldn't.

Dave



Mon, 13 Sep 2004 00:10:43 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value


Quote:

> Y> It does not store the evaluated default value.

>  Yes, you are right. Sorry for the misinformation

Quoting from your and Matz's solutions back in January  (search
Google-news for `multi-dimensional Hash group:comp.lang.ruby')
you have to write this as

class MatzHash < Hash
  def default(key)
    self[key] = type.new
   # happy type-mutating;-))
  end
end

class TsHash < Hash
   def initialize
     super do |l,r| self[r] = type.new  end
     # super  do |l,r| l[r] = type.new  end
     # works too - which does not seem right too me
     # I guess Matz intended that the arguments
     # l,r take on the values key,value ...
   end
end

Quote:

> Y>  Should it?

>  It depend if you want that it work like a P language (not really a good
>  reference for me :-)))

No arguments here;-))

/Christoph



Mon, 13 Sep 2004 00:33:45 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Quote:
> Hi -

Hi too,

Quote:
> In the documentation for the 'new' method in the Hash class in Programming
> Ruby it says that 'anObject' will be used as default value, but consider the
> following example:
> var = Hash.new(Hash.new)

The documentation is true. It says that *anObject*, i.e. the reference
to an (better *one* here) object is used as default value!

So a new Hash will be created. That *one* instance will be passed to
Hash::new as default value to be used, if a certain key does not exist.

Quote:
> var['index1'] = 'value1'
> var['index2']['index22'] = 'value22'

Because 'index2' does not exist, the instance serving as default value
will be returned. *That* instance will get sent the []= message and
therefore insert a association between key 'index22' and 'value22'.

The default Hash instance contains now { 'index22' => 'value22' }

Quote:
> var['index3']['index32'] = 'value32'

And here happens the same again. So after this line the Hash instance
used as default value contain now:

  { 'index22' => 'value22', 'index32' => 'value32' }

Quote:
> var['index4'] = 'value4'
> p var['donotexist']
> Why does "p var['donotexist']" output {"index32" => "value32", "index22" =>
> "value22"} - and _not_ just {} (a new Hash)?

You have passed a default *value* to Hash::new above. That value
happens to be the reference to a new created Hash instance. The
reference of this one Hash instance is returned every time you try to
access a key that does not exist.

Look this:

  puts( var['index3'].id == var['donotexist'].id )

you see? Every time the *same* Hash instance is returned to you if you
try to access a key that does not exist.

In Ruby 1.7.x it is possible to do this:

  var = Hash.new { Hash.new }

Now every time a key was not found, the block will be executed
returning a brand new Hash instance.

Quote:
> If it's no bug, I think it's a bug in documentation. - and not a very logic
> behavior.

OTOH, I think it is a very logic and usefull behavior. Especially as
we have now the block supporting Hash::new method :-)

HTH,
\cle
--



Mon, 13 Sep 2004 00:38:44 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Quote:

> Hi,

> In message "Re: Hash.new(Hash.new) doesn't use Hash.new as default value"

> | With 1.7 you'll have the possibility to write
> |
> | Hash.new { Hash.new }
> |
> | and each times a key is not defined, ruby will evaluate the block, the
> | result of the block will be stored in the Hash and ruby will
> do what you
> | want.

> It does not store the evaluated default value.  Should it?

Do you mean something like

#----------------- 8< ------------------
h = Hash.new { |key| "There is no entry for '#{key.to_s}'" }

h["here"] = "OK"
puts h["missing"] # prints "There is no entry for 'missing'"

h.each{ |k,v| puts "#{k} => #{v} }
# prints
#   "here => OK"
#   "missing => There is no entry for 'missing'"
#----------------- 8< ------------------

Might be nice to allow returning one computed default value, but storing a
different computed default value.

James

- Show quoted text -

Quote:

>                                                    matz.



Mon, 13 Sep 2004 00:48:33 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value
Hi,

In message "Re: Hash.new(Hash.new) doesn't use Hash.new as default value"

|Perhaps the distinction is whether it's being used as an lvalue or an
|rvalue. As an lvalue, it should be stored, but as an rvalue it
|probably shouldn't.

Sounds interesting.  Unfortunately, there's no way to distinguish
lvalue and rvalue.

                                                        matz.



Mon, 13 Sep 2004 01:27:21 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value

Quote:

> |Perhaps the distinction is whether it's being used as an lvalue or an
> |rvalue. As an lvalue, it should be stored, but as an rvalue it
> |probably shouldn't.

> Sounds interesting.  Unfortunately, there's no way to distinguish
> lvalue and rvalue.

OK - plan B

Rather than have the block simply return a default value, give it
enough context to let it assign that value or not:

  h = Hash.new { 0 }    # simply return 0, do not alter the hash

  h = Hash.new { |hash, key| hash[key] = Hash.new } # put a new hash
                                                    # in place

That gives control back to the developer.

Dave



Mon, 13 Sep 2004 02:05:31 GMT  
 Hash.new(Hash.new) doesn't use Hash.new as default value
Hi,

In message "Re: Hash.new(Hash.new) doesn't use Hash.new as default value"

|Rather than have the block simply return a default value, give it
|enough context to let it assign that value or not:
|
|  h = Hash.new { 0 }    # simply return 0, do not alter the hash
|
|  h = Hash.new { |hash, key| hash[key] = Hash.new } # put a new hash
|                                                    # in place
|
|That gives control back to the developer.

Fortunately, it already works exactly you described.

                                                        matz.



Mon, 13 Sep 2004 02:53:58 GMT  
 
 [ 18 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Hash.new {block} / Hash#default_proc{,_set}

2. Hash compression (Hash 'consing') circa 1957

3. Sorting a Hash by value of integer stored in the Hash

4. Hash compression (Hash 'consing') circa 1957

5. Hash compression (Hash 'consing') circa 1957

6. obj.hash now == obj.hash after?

7. hash as key in hash

8. Hash#index !==> Hash#indexes

9. Hash#index !==> Hash#indexes

10. Moron hashing (rehashing hashing again)

11. hash of hashes via ObjTypes?

12. New Proposed SHA-256 Hash

 

 
Powered by phpBB® Forum Software