[ruby-core:122305] [Ruby Bug#21376] Inconsistent equality between Sets with different compare_by_identity, different classes

Issue #21376 has been reported by Ethan (Ethan -). ---------------------------------------- Bug #21376: Inconsistent equality between Sets with different compare_by_identity, different classes https://bugs.ruby-lang.org/issues/21376 * Author: Ethan (Ethan -) * Status: Open * ruby -v: ruby 3.5.0dev (2025-05-26T17:42:35Z master 909a0daab6) +PRISM [x86_64-darwin22] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- This is an inconsistency between the new core Set and the ruby-implemented Set. I think probably the new implementation's behavior seems correct and the ruby implementation is an incorrect edge case. ```ruby class MySet < Set end o = Object.new Set.new([o]).compare_by_identity == MySet.new([o]) # => false on 3.5.0; true with the ruby implementation ``` My understanding is that, for Hash, if two hashes have unequal `compare_by_identity?` they are never equal (even if containing identical contents), unless both are empty. It would make sense for Set to be the same. Hmm, analyzing the ruby Set#== a bit more, I see a further edge case where a non-identity set is considered equal to an identity set with as few as one element in common. ```ruby set_by_eq = Set.new(['a', 'b', 'c']) # => #<Set: {"a", "b", "c"}> set_by_id = MySet.new.compare_by_identity.merge(['a', 'a'.dup, 'a'.dup]) # => #<MySet: {"a", "a", "a"}> set_by_eq == set_by_id # => true in the ruby set, false in core set set_by_id == set_by_eq # => false in both ``` The latter seems unlikely it would ever be triggered unintentionally. The former I did happen across, but since I think the new behavior is correct, I will not be affected when I fix my code to consistently compare_by_identity. Given that, it may be questionable whether it's worth fixing. -- https://bugs.ruby-lang.org/

Issue #21376 has been updated by jeremyevans0 (Jeremy Evans). This was reported as a bug. Can you explain what you think is the bug in the current core Set implementation? From your description, it sounds like core Set fixed a bug in stdlib set. ---------------------------------------- Bug #21376: Inconsistent equality between Sets with different compare_by_identity, different classes https://bugs.ruby-lang.org/issues/21376#change-113456 * Author: Ethan (Ethan -) * Status: Open * ruby -v: ruby 3.5.0dev (2025-05-26T17:42:35Z master 909a0daab6) +PRISM [x86_64-darwin22] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- This is an inconsistency between the new core Set and the ruby-implemented Set. I think probably the new implementation's behavior seems correct and the ruby implementation is an incorrect edge case. ```ruby class MySet < Set end o = Object.new Set.new([o]).compare_by_identity == MySet.new([o]) # => false on 3.5.0; true with the ruby implementation ``` My understanding is that, for Hash, if two hashes have unequal `compare_by_identity?` they are never equal (even if containing identical contents), unless both are empty. It would make sense for Set to be the same. Hmm, analyzing the ruby Set#== a bit more, I see a further edge case where a non-identity set is considered equal to an identity set with as few as one element in common. ```ruby set_by_eq = Set.new(['a', 'b', 'c']) # => #<Set: {"a", "b", "c"}> set_by_id = MySet.new.compare_by_identity.merge(['a', 'a'.dup, 'a'.dup]) # => #<MySet: {"a", "a", "a"}> set_by_eq == set_by_id # => true in the ruby set, false in core set set_by_id == set_by_eq # => false in both ``` The latter seems unlikely it would ever be triggered unintentionally. The former I did happen across, but since I think the new behavior is correct, I will not be affected when I fix my code to consistently compare_by_identity. Given that, it may be questionable whether it's worth fixing. -- https://bugs.ruby-lang.org/

Issue #21376 has been updated by Ethan (Ethan -). I am not certain what behavior is intended as correct - the 3.5 one seems correct to me but I am no expert. Then assuming the 3.5 behavior is correct, don't know if backporting a fix to supported versions with ruby Set is desirable. If it's not worth backporting, close the issue, I have no problem with that. ---------------------------------------- Bug #21376: Inconsistent equality between Sets with different compare_by_identity, different classes https://bugs.ruby-lang.org/issues/21376#change-113459 * Author: Ethan (Ethan -) * Status: Open * ruby -v: ruby 3.5.0dev (2025-05-26T17:42:35Z master 909a0daab6) +PRISM [x86_64-darwin22] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- This is an inconsistency between the new core Set and the ruby-implemented Set. I think probably the new implementation's behavior seems correct and the ruby implementation is an incorrect edge case. ```ruby class MySet < Set end o = Object.new Set.new([o]).compare_by_identity == MySet.new([o]) # => false on 3.5.0; true with the ruby implementation ``` My understanding is that, for Hash, if two hashes have unequal `compare_by_identity?` they are never equal (even if containing identical contents), unless both are empty. It would make sense for Set to be the same. Hmm, analyzing the ruby Set#== a bit more, I see a further edge case where a non-identity set is considered equal to an identity set with as few as one element in common. ```ruby set_by_eq = Set.new(['a', 'b', 'c']) # => #<Set: {"a", "b", "c"}> set_by_id = MySet.new.compare_by_identity.merge(['a', 'a'.dup, 'a'.dup]) # => #<MySet: {"a", "a", "a"}> set_by_eq == set_by_id # => true in the ruby set, false in core set set_by_id == set_by_eq # => false in both ``` The latter seems unlikely it would ever be triggered unintentionally. The former I did happen across, but since I think the new behavior is correct, I will not be affected when I fix my code to consistently compare_by_identity. Given that, it may be questionable whether it's worth fixing. -- https://bugs.ruby-lang.org/

Issue #21376 has been updated by knu (Akinori MUSHA). This bug in optimization in Set#== deserves to be fixed, I think. In hindsight, adding Set#compare_by_identity might not have been the best idea. ---------------------------------------- Bug #21376: Inconsistent equality between Sets with different compare_by_identity, different classes https://bugs.ruby-lang.org/issues/21376#change-113640 * Author: Ethan (Ethan -) * Status: Open * ruby -v: ruby 3.5.0dev (2025-05-26T17:42:35Z master 909a0daab6) +PRISM [x86_64-darwin22] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- This is an inconsistency between the new core Set and the ruby-implemented Set. I think probably the new implementation's behavior seems correct and the ruby implementation is an incorrect edge case. ```ruby class MySet < Set end o = Object.new Set.new([o]).compare_by_identity == MySet.new([o]) # => false on 3.5.0; true with the ruby implementation ``` My understanding is that, for Hash, if two hashes have unequal `compare_by_identity?` they are never equal (even if containing identical contents), unless both are empty. It would make sense for Set to be the same. Hmm, analyzing the ruby Set#== a bit more, I see a further edge case where a non-identity set is considered equal to an identity set with as few as one element in common. ```ruby set_by_eq = Set.new(['a', 'b', 'c']) # => #<Set: {"a", "b", "c"}> set_by_id = MySet.new.compare_by_identity.merge(['a', 'a'.dup, 'a'.dup]) # => #<MySet: {"a", "a", "a"}> set_by_eq == set_by_id # => true in the ruby set, false in core set set_by_id == set_by_eq # => false in both ``` The latter seems unlikely it would ever be triggered unintentionally. The former I did happen across, but since I think the new behavior is correct, I will not be affected when I fix my code to consistently compare_by_identity. Given that, it may be questionable whether it's worth fixing. -- https://bugs.ruby-lang.org/
participants (3)
-
Ethan (Ethan -)
-
jeremyevans0 (Jeremy Evans)
-
knu (Akinori MUSHA)