From: tenderlove@... Date: 2018-03-14T23:54:43+00:00 Subject: [ruby-core:86116] [Ruby trunk Bug#14573] rb_ary_or doesn't check objects hash when the array contains less than SMALL_ARRAY_LEN Issue #14573 has been updated by tenderlovemaking (Aaron Patterson). I guess I can see how this is a behavior change, but these two objects shouldn't `eql?` each other. It seems like a bug in the `eql?` implementation of the `X` class. These instances won't deal with hash collisions correctly, so I'm not sure why we'd expect union operator to work too. ---------------------------------------- Bug #14573: rb_ary_or doesn't check objects hash when the array contains less than SMALL_ARRAY_LEN https://bugs.ruby-lang.org/issues/14573#change-70985 * Author: Willian (Willian van der Velde) * Status: Open * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17] * Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN ---------------------------------------- Hello, While debugging a build failure on a 2.5 branch of graphql-ruby (https://github.com/rmosolgo/graphql-ruby/pull/1303) we found out a difference in behavior for the Array's union operator. On Ruby 2.5: ~~~ ruby irb(main):001:0> class X; def initialize(h); @h = h; end; def hash; @h; end; def eql?(o); true; end; end => :eql? irb(main):002:0> a = X.new(1) ; b = X.new(2) => # irb(main):003:0> a.hash => 1 irb(main):004:0> b.hash => 2 irb(main):005:0> [a] | [b] => [#] ~~~ I would expect this union would result in two objects. On Ruby 2.3.6 I do get two objects: ~~~ ruby irb(main):001:0> class X; def initialize(h); @h = h; end; def hash; @h; end; def eql?(o); true; end; end => :eql? irb(main):002:0> a = X.new(1) ; b = X.new(2) => # irb(main):003:0> a.hash => 1 irb(main):004:0> b.hash => 2 irb(main):005:0> [a] | [b] => [#, #] ~~~ I think this change is related to #13884, and it looks like when small arrays (less than SMALL_ARRAY_LEN) are given the object's hash isn't checked. If a bigger array is given we get a correct union: ~~~ ruby irb(main):001:0> class X; def initialize(h); @h = h; end; def hash; @h; end; def eql?(o); true; end; end => :eql? irb(main):002:0> a = 20.times.map { |i| X.new(i) } => ... irb(main):003:0> b = 20.times.map { |i| X.new(100 + i) } => ... irb(main):004:0> (a | b).size => 40 ~~~ Thanks, Willian -- https://bugs.ruby-lang.org/ Unsubscribe: