Issue #12970 has been updated by Piotr Szmielew.


In this particular example even manually rehashing internal hash doesn't quite work...

~~~ ruby
s = Set.new
t = Set.new
s << [s]
t << [t]
s == t # => false
s.instance_variable_get(:@hash).rehash
t.instance_variable_get(:@hash).rehash
s == t # => false
~~~


So this isn't issue with rehashing, therefore my patch definitely wouldn't work here.

There is another solution - when comparing sets, use hash method calculate hashes and compare them. Code would look like this:
~~~ ruby
  def ==(other)
    if self.equal?(other)
      true
    elsif other.instance_of?(self.class)
      @hash.keys.hash == other.instance_variable_get(:@hash).keys.hash
    elsif other.is_a?(Set) && self.size == other.size
      other.all? { |o| @hash.keys.map(&:hash).include?(o.hash) }
    else
      false
    end
  end

~~~

With this approach, examples you provided works correctly.

Let me know if this acceptable solution and should I provide patch.

Marc-Andre Lafortune wrote:
> That's not going to cut it... There are many other counter examples....
> 
> ```
> s = Set.new
> t = Set.new
> s << [s]
> t << [t]
> s == t # => false
> ```
> 
> or similarly:
> 
> ```
> s = Set.new
> t = Set.new
> a = Set.new([s])
> b = Set.new([t])
> s << a
> t << b
> s == t # => false
> ```

----------------------------------------
Bug #12970: == Equality of recursive sets fails
https://bugs.ruby-lang.org/issues/12970#change-62264

* Author: Kevin de Berk
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 2.2.5, 2.3.3
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
Comparing recursive arrays and hashes with equal? contents (save for the recursive element) using == succeeds.
However, using == to compare two recursive sets with equal? contents fails. I expect that to succeed.

See the attached script. This is my output for 2.2.5 and 2.3.3:

~~~
[1, 2, 3] == [1, 2, 3]? -> true
[1, 2, 3, [...]] == [1, 2, 3, [...]]? -> true
{:a=>1, :b=>2} == {:a=>1, :b=>2}? -> true
{:a=>1, :b=>2, :c=>{...}} == {:a=>1, :b=>2, :c=>{...}}? -> true
#<Set:0x00000001f90fc8> == #<Set:0x00000001f90500>? -> true
#<Set:0x00000001f92968> == #<Set:0x00000001f91478>? -> false
~~~


---Files--------------------------------
recursive_set_comparison.rb (871 Bytes)
fix_recursive_sets.patch (2.39 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>