From: merch-redmine@... Date: 2020-09-02T19:33:08+00:00 Subject: [ruby-core:99850] [Ruby master Bug#14437] Integer == doesn't work with coerce since 2.4 (and != since 1.9). Should it? Issue #14437 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Closed taw (Tomasz Wegrzanowski) wrote in #note-2: > Looking at the code fix_equal(x,y) when y was of non-core class used to call num_equal,(x,y) which then did reverse call for y==x, > so it was possible to have custom classes, which have meaningful interaction with 42 == obj > > It still does this, except now it casts the result to true/false. > > ~~~ > static VALUE > num_equal(VALUE x, VALUE y) > { > VALUE result; > if (x == y) return Qtrue; > result = num_funcall1(y, id_eq, x); > if (RTEST(result)) return Qtrue; > return Qfalse; > } > ~~~ > > I can see it comes from this change https://github.com/ruby/ruby/commit/ffa371d9aa1af1f22c41063add9af3e4922f2f12 > > > Why was this changed? It's messing up with my use case here, and there's a bunch of other ruby code (like rspec) > which make == return something else than true/false. The `Integer#==` method is documented to only return true or false (see https://docs.ruby-lang.org/en/master/Integer.html#method-i-3D-3D), so returning other values would be considered a bug. Code that wants `==` to return a custom value should now use `obj == integer` instead of `integer == obj`. ---------------------------------------- Bug #14437: Integer == doesn't work with coerce since 2.4 (and != since 1.9). Should it? https://bugs.ruby-lang.org/issues/14437#change-87377 * Author: taw (Tomasz Wegrzanowski) * Status: Closed * Priority: Normal * ruby -v: 2.5.0 * Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN ---------------------------------------- Here's extracted test sample: ~~~ruby class Item def initialize(value) @value = value end def coerce(other) [Item.new(other), self] end def ==(other) Item.new("#{inspect} == #{other.inspect}") end def !=(other) Item.new("#{inspect} != #{other.inspect}") end def inspect "(#{@value})" end end a = Item.new("a") p [RUBY_VERSION, 42 == a, 42 != a, a == 42, a == a, a != 42, a != a] ~~~ I'd expect it to print: `["2.x.x", ((a) == 42), ((a) != 42), ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))]` What happens instead is: ~~~ ["1.9.3", ((a) == 42), false, ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))] ["2.2.0", ((a) == 42), false, ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))] ["2.3.3", ((a) == 42), false, ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))] ["2.4.1", true, false, ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))] ["2.5.0", true, false, ((a) == 42), ((a) == (a)), ((a) != 42), ((a) != (a))] ~~~ So != never used coerce, and now == doesn't use coerce either. Using Bignum value instead of 42 in this example breaks it even pre-2.4. So, the question is: * is using coerce like this not supported, and it was just an accident that it used to work? (and I should redefine Integer#== and Integer#!=) * or is it meant to work, and it's a ruby bug? For context, it's a problem for z3 gem, which builds big mathematical expressions like Z3.Int("a")+Z3.Int("b") == 4 and then uses Microsoft Z3 solver to solve them. Not being able to use == / != because of this issue would really reduce its usability. Using coerce this way works just fine with +, -, *, >=, etc., it's just == and != which don't work. -- https://bugs.ruby-lang.org/ Unsubscribe: