Bug #1885
closedProper comparison of recursive Struct & Range
Description
=begin
The following code freezes the latest ruby 1.9:
MyClass = Struct.new(:foo)
x = MyClass.new; x[:foo] = x
y = MyClass.new; 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
super(self..self)
end
def <=>(x)
0 # Needed so CrazyRange can be the begin and end values of a range...
end
end
CrazyRange.new == CrazyRange.new # 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)
=end
Files
Updated by marcandre (Marc-Andre Lafortune) over 15 years ago
- File struct_comparison.diff struct_comparison.diff added
=begin
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.
=end
Updated by marcandre (Marc-Andre Lafortune) over 15 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
=begin
Applied in changeset r25010.
=end