Project

General

Profile

Actions

Bug #18470

closed

Union of two identical sets produces a set with duplicate members

Added by smokinggun (John Weir) 9 months ago. Updated 9 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-linux]
[ruby-core:107028]

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

set_test.rb (348 Bytes) set_test.rb smokinggun (John Weir), 01/10/2022 08:22 PM

Updated by byroot (Jean Boussier) 9 months 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) 9 months 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) 9 months ago

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?

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) 9 months 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 be Set#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) 9 months ago

Set#reset

Ah, that's the rehash equivalent I didn't see.

Yeah, I think we can close.

Actions #6

Updated by byroot (Jean Boussier) 9 months ago

  • Status changed from Open to Closed
Actions

Also available in: Atom PDF