From: zomg.tim@... Date: 2016-10-22T10:48:03+00:00 Subject: [ruby-core:77713] [Ruby trunk Bug#12864] Regression comparing Integer (Fixnum) to Comparable (2.4.0-preview2) Issue #12864 has been reported by Tim Peters. ---------------------------------------- Bug #12864: Regression comparing Integer (Fixnum) to Comparable (2.4.0-preview2) https://bugs.ruby-lang.org/issues/12864 * Author: Tim Peters * Status: Open * Priority: Normal * Assignee: * ruby -v: * Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN ---------------------------------------- If you have a class including `Comparable` and expecting to be compared to `Integer`, equality test doesn't work anymore. This worked in 2.3.1. Example: ~~~ruby class MyInteger include Comparable def initialize(i) @i = i.to_i end attr_reader :i def <=>(other) @i <=> (other.is_a?(MyInteger) ? other.i : other) end end [5, 2**62, 2**61].each do |i| puts MyInteger.new(i) == i puts i == MyInteger.new(i) end ~~~ Output in 2.3.1 and expected output: ~~~ true true true true true true ~~~ Output in 2.4.0-preview2: ~~~ true false true true true ../test5.rb:16:in `==': invalid inspect_tbl pair_list for :== in # (TypeError) from ../test5.rb:16:in `block in
' from ../test5.rb:14:in `each' from ../test5.rb:14:in `
' ~~~ As shown, if the `MyInteger` version is the left hand side of `==`, the comparison works as expected. If the `Integer` is on the left hand side, then the problem depends on its size: * If it is big enough that it is actually a Bignum (`<= -(2**62-1)` or `>= 2**62`) then it compares true as expected * If it is a smallish fixnum (between `-(2**61)` and `2**61-1`) then it incorrectly compares false * For large fixnums not covered above (eg `2**61`) the comparison raises a `TypeError`. This does NOT affect other Comparable methods. Eg, less than/greater than. `3 < MyInteger.new(4)` works, as long as `coerce` is defined. The examples above never try to call coerce. A workaround is to define `==` on our class. If this is done the above tests all print true: ```ruby def MyInteger def ==(other) @i == (other.is_a?(MyInteger) ? other.i : other) end end ``` However this shouldn't be necessary since `Comparable` is adding an equality method. Using bisect, I am pretty sure this regression was introduced in r55891. -- https://bugs.ruby-lang.org/ Unsubscribe: