On Wed, 20 Dec 2006, Tim Pease wrote:

> A little, little more robust ...
>
> def ==( other )
> return false unless self.class === other
>
> self.instance_variables.each do |v|
>   return false unless self.instance_variable_get(v) ==
>       other.instance_variable_get(v)
> end
> true
> end


careful:


   harp:~ > cat a.rb
   class C
     def initialize
       @this = self
     end
     def ==( other )
       return false unless self.class === other
       self.instance_variables.each do |v|
         return false unless self.instance_variable_get(v) ==
             other.instance_variable_get(v)
       end
       true
     end
   end

   C.new == C.new


   harp:~ > ruby a.rb
   a.rb:8:in `==': stack level too deep (SystemStackError)
           from a.rb:10:in `=='
           from a.rb:8:in `=='
           from a.rb:10:in `=='
           from a.rb:8:in `=='
           from a.rb:10:in `=='
           from a.rb:8:in `=='
           from a.rb:10:in `=='
           from a.rb:8:in `=='
            ... 2489 levels...
           from a.rb:8:in `=='
           from a.rb:10:in `=='
           from a.rb:8:in `=='
           from a.rb:16


i prefer this pattern for the self documenting properties:

   harp:~ > cat a.rb
   class C
     %w[ a b c ].each{|a| attr a}
     def initialize a, b, c
       @a, @b, @c = a, b, c
     end
     CMP_ATTRS = %w[ a b c ]
     def == other
       begin
         x = CMP_ATTRS.map{|a| send a }
         y = CMP_ATTRS.map{|a| other.send a }
         x == y
       rescue
         false
       end
     end
   end

   p(  C.new(1,2,3) == C.new(1,2,3)  )
   p(  C.new(1,2,3) == C.new(2,3,4)  )


   harp:~ > ruby a.rb
   true
   false


though it too suffers from cyclical structures...  sigh.

-a
-- 
if you find yourself slandering anybody, first imagine that your mouth is
filled with excrement.  it will break you of the habit quickly enough. - the
dalai lama