Bug #18470
closedUnion of two identical sets produces a set with duplicate members
Description
We came across an issue where the union of two identical sets produced a non uniq Set.
We noticed this when upgrading from 2.7.1 to 3.1
See the attached test, the last assertion fails
C = Struct.new :id
a = Set.new
b = Set.new
f = C.new
a << f
f.id = 1
b << f
a + b
# => #<Set: {#<struct C id=1>, #<struct C id=1>}>
b + a
# => #<Set: {#<struct C id=1>}>
(a + b).uniq
=> [#<struct C id=1>]
Files
Updated by byroot (Jean Boussier) almost 3 years ago
The tricky part is that the object is mutated after being inserted, so it's sounds like a rehash no longer happens, possibly because of https://bugs.ruby-lang.org/issues/16996.
It may or may not be considered a bug, I'll see what it would take to fix it though.
Also this might have more its place on https://github.com/ruby/set/issues
Updated by byroot (Jean Boussier) almost 3 years ago
So it's indeed a rehash issue: https://github.com/casperisfine/set/commit/40ff2f907118d8766217bbe8ac27119111050217
Also it seems @marcandre (Marc-Andre Lafortune) knew about this case (or similar), based on the description of the issue I linked.
The main problem is that Set
doesn't expose a rehash
method, so there's not really any way to workaround it. Maybe it should?
Updated by smokinggun (John Weir) almost 3 years ago
The main problem is that
Set
doesn't expose arehash
method, so there's not really any way to workaround it. Maybe it should?
The rehash works. Should add
also have a rehash?
C = Struct.new :id
a = Set.new
f = C.new
a << f
f.id = 1
a << f
# => #<Set: {#<struct C id=1>, #<struct C id=1>}>
Updated by ufuk (Ufuk Kayserilioglu) almost 3 years ago
Doesn't the following from https://bugs.ruby-lang.org/issues/16996 address this issue?
...
Today, it is official that sets with elements that are later mutated must beSet#reset
, so it is official that this should not be relied upon.
...
It seems like this is not a bug and the outcome is expected without a call to Set#reset
:
C = Struct.new :id
a = Set.new
b = Set.new
f = C.new
a << f
f.id = 1
b << f
a.reset
# => #<Set: {#<struct C id=1>}>
a + b
# => #<Set: {#<struct C id=1>}>
b + a
# => #<Set: {#<struct C id=1>}>
Updated by byroot (Jean Boussier) almost 3 years ago
Set#reset
Ah, that's the rehash equivalent I didn't see.
Yeah, I think we can close.
Updated by byroot (Jean Boussier) almost 3 years ago
- Status changed from Open to Closed