The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Recursive data structures, #hash and #eql?

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Eigen Class

Posts: 358
Nickname: eigenclass
Registered: Oct, 2005

Eigenclass is a hardcore Ruby blog.
Recursive data structures, #hash and #eql? Posted: Nov 25, 2005 1:54 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Eigen Class.
Original Post: Recursive data structures, #hash and #eql?
Feed Title: Eigenclass
Feed URL: http://feeds.feedburner.com/eigenclass
Feed Description: Ruby stuff --- trying to stay away from triviality.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Eigen Class
Latest Posts From Eigenclass

Advertisement

In ruby-talk:167185, I showed a way to use hashes as keys in hashes without degrading the efficiency of the hash (too much). It involved creating objects on the fly with the appropriate #eql? and #hash methods, as we often do with hashes.

Some time later, I realized it would fail horribly (SystemStackError) if the hash contained itself (or one of its elements did, transitively). And then I asked myself, "am I really doing it that much worse than Ruby?". We know that the semantics of Hash#{eql?,hash} are such that "recursive hashes" are fine, but what about their cousin, Array?

 [RUBY_VERSION, RUBY_RELEASE_DATE]  # => ["1.8.3", "2005-09-24"]
 W = lambda{|x|x<<x}
 W[[]].hash                         # => 
 # ~> -:3:in `hash': stack level too deep (SystemStackError)
 # ~> 	from -:3

"Mmmm surely 1.9 will know better":

 [RUBY_VERSION, RUBY_RELEASE_DATE]  # => ["1.9.0", "2005-11-03"]
 W = lambda{|x|x<<x}
 W[[]].hash                         # => 2
 W[[]].eql? W[[]]                   # => 
 # ~> -:4:in `eql?': stack level too deep (SystemStackError)
 # ~> 	from -:4

Alright, so Hash#hash got wiser, but eql? is still doing a recursive element-by-element comparison.

Just to make sure, let's verify that Hash#{eql?,hash} can handle recursion (by not handling it at all, that is...)

 W2 = lambda{|x| x[x] = x}
 W2[{}].hash                        # => -605020064
 W2[{}].hash                        # => -605020114
 W2[{}].eql? W2[{}]                 # => false
 W2[{}] == W2[{}]                   # => false
 {} == {}                           # => true
 {1=>{}} == {1=>{}}                 # => true
 { {}=>1 } == { {}=>1 }             # => false

The two last lines differ because

 {} == {}                           # => true
 {}.eql?({})                        # => false
 

We finally arrive to our small challenge:

Can we create an Array#eql? method able to withstand recursive data structures consisting of arrays?

The default definition (rb_ary_eql) is essentially equivalent to:

 class Array
   def eql?(o) # !> method redefined; discarding old eql?
     return true if o.object_id == object_id
     return false unless Array === o
     return false if o.size != size
     
     size.times{|i| return false unless self[i].eql? o[i] }
     true
   end
 end

Let's verify that is behaves as badly as the default one. The handy lambda we've been using is called W because it's reminiscent of the Omega combinator:

 W = lambda{|x|x<<x}
 W[[]].eql? W[[]]                   # => 
                           
 # ~> -:3:in `eql?': stack level too deep (SystemStackError)
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	 ... 4477 levels...
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:7:in `eql?'
 # ~> 	from -:16

Great, this shows we have something to play with.


Read more...

Read: Recursive data structures, #hash and #eql?

Topic: Migrating Old DBs with Migrations Previous Topic   Next Topic Topic: Ruby Kata One -- Supermarket Pricing

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use