[ruby-core:125397] [Ruby Bug#22021] Array#delete_if may delete wrong object if array has been altered already
Issue #22021 has been reported by chucke (Tiago Cardoso). ---------------------------------------- Bug #22021: Array#delete_if may delete wrong object if array has been altered already https://bugs.ruby-lang.org/issues/22021 * Author: chucke (Tiago Cardoso) * Status: Open * ruby -v: 4.0.2 * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The simplest example I can come up with: ```ruby $ar = ar = [1, 2, 3, 4, 5] def delete_at(i) $ar.delete(i) end ar.delete_if { |i| i == 2 ? (delete_ar(i) && true) : false } ar #=> [1, 4, 5], and it should be [1, 3, 4, 5] ``` -- https://bugs.ruby-lang.org/
Issue #22021 has been updated by Eregon (Benoit Daloze). IMO it's not reasonable for `Array#delete_if` to do anything else than what it already does. How can `Array#delete_if` know which element you deleted and whether it should delete or not? The block returns true for the second 2nd call, so it should delete the 2nd element after that block call (unless the Array#size < index when it's noop then). ---------------------------------------- Bug #22021: Array#delete_if may delete wrong object if array has been altered already https://bugs.ruby-lang.org/issues/22021#change-117169 * Author: chucke (Tiago Cardoso) * Status: Open * ruby -v: 4.0.2 * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The simplest example I can come up with: ```ruby $ar = ar = [1, 2, 3, 4, 5] def del(i) $ar.delete(i) end ar.delete_if { |e| e == 2 ? (del(e) && true) : false } p ar #=> [1, 4, 5], and it should be [1, 3, 4, 5] ``` -- https://bugs.ruby-lang.org/
Issue #22021 has been updated by Eregon (Benoit Daloze). Status changed from Open to Rejected I think this is safe to reject, I think it's not feasible to change this. One should avoid mutating the Array while iterating, otherwise this kind of behavior is expected. ---------------------------------------- Bug #22021: Array#delete_if may delete wrong object if array has been altered already https://bugs.ruby-lang.org/issues/22021#change-117170 * Author: chucke (Tiago Cardoso) * Status: Rejected * ruby -v: 4.0.2 * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The simplest example I can come up with: ```ruby $ar = ar = [1, 2, 3, 4, 5] def del(i) $ar.delete(i) end ar.delete_if { |e| e == 2 ? (del(e) && true) : false } p ar #=> [1, 4, 5], and it should be [1, 3, 4, 5] ``` -- https://bugs.ruby-lang.org/
Issue #22021 has been updated by chucke (Tiago Cardoso). I get the point of avoiding mutating while iterating, but the point of `delete_if` is to mutate the array. there's nothing in its name hinting at it being based on the index, that's what `#delete_at` is for, so that's an implementation detail. I didn't check the implementation yet, so I may be oversimplifying it, but I don't see why the element ref can't be kept for post-comparison (although, if based on the `#each` impl, which is known to skip elements on mutation, I can understand your judgement). ---------------------------------------- Bug #22021: Array#delete_if may delete wrong object if array has been altered already https://bugs.ruby-lang.org/issues/22021#change-117205 * Author: chucke (Tiago Cardoso) * Status: Rejected * ruby -v: 4.0.2 * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The simplest example I can come up with: ```ruby $ar = ar = [1, 2, 3, 4, 5] def del(i) $ar.delete(i) end ar.delete_if { |e| e == 2 ? (del(e) && true) : false } p ar #=> [1, 4, 5], and it should be [1, 3, 4, 5] ``` -- https://bugs.ruby-lang.org/
Issue #22021 has been updated by Eregon (Benoit Daloze). The only way to iterate an Array is to use an index from 0 to size, so it's always going to be based on index. chucke (Tiago Cardoso) wrote in #note-4:
I don't see why the element ref can't be kept for post-comparison
What if you have `[1, 2, 2, 2, 2, 3, 4, 5, 2]`, how would `delete_if` find out if one of the `2` was removed concurrently? There could also be another Thread writing to the Array, so checking if the element is the same before yielding to the block and after is inherently brittle and unreliable. ---------------------------------------- Bug #22021: Array#delete_if may delete wrong object if array has been altered already https://bugs.ruby-lang.org/issues/22021#change-117212 * Author: chucke (Tiago Cardoso) * Status: Rejected * ruby -v: 4.0.2 * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The simplest example I can come up with: ```ruby $ar = ar = [1, 2, 3, 4, 5] def del(i) $ar.delete(i) end ar.delete_if { |e| e == 2 ? (del(e) && true) : false } p ar #=> [1, 4, 5], and it should be [1, 3, 4, 5] ``` -- https://bugs.ruby-lang.org/
participants (2)
-
chucke (Tiago Cardoso) -
Eregon (Benoit Daloze)