Bug #1885

Proper comparison of recursive Struct & Range

Added by marcandre (Marc-Andre Lafortune) almost 11 years ago. Updated about 9 years ago.

Target version:
ruby -v:
ruby 1.9.2dev (2009-08-05 trunk 24397) [i386-darwin9.7.0]


The following code freezes the latest ruby 1.9:

MyClass =
x =; x[:foo] = x
y =; y[:foo] = y
x == y # Loops forever (can not be interrupted)

Solution: rb_struct_equal & rb_struct_eql should handle recursion in a similar fashion as Array and Hash (i.e. by calling rb_exec_recursive_paired and returning Qtrue if recursion is detected). I could make a patch if needed.

Searching the source code for rb_exec_recursive revealed that Range is potentially recursive too (see range_inspect). The ==, eql? and === methods do not call rb_exec_recursive_paired and are thus also potentially troublesome. To build a recursive Range is not trivial though; either some intermediate container class is needed or else some crazy thing like:

class CrazyRange < Range
def initialize

 def <=>(x)
   0   # Needed so CrazyRange can be the begin and end values of a range...

end == # Loops forever (can not be interrupted)

I'm not sure that it is worth modifying ==, eql? and === to use rb_exec_recursive_paired and make them bulletproof.

Note that both Struct#hash and Range#hash face the same issue than Array#hash & Hash#hash (see issue #1852)


struct_comparison.diff (1.94 KB) struct_comparison.diff marcandre (Marc-Andre Lafortune), 08/31/2009 04:17 AM

Updated by marcandre (Marc-Andre Lafortune) over 10 years ago

Here is a patch for the latest 1.9.x that fixes comparison between recursive Struct. The right result is now returned, instead of looping forever. Note: this fixes Struct only; Range has not been patched. Rubyspecs have been updated.


Updated by marcandre (Marc-Andre Lafortune) over 10 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r25010.

Also available in: Atom PDF