[#77789] [Ruby trunk Feature#12012] Add Boolean method — prodis@...
Issue #12012 has been updated by Fernando Hamasaki de Amorim.
4 messages
2016/10/27
[ruby-core:77713] [Ruby trunk Bug#12864] Regression comparing Integer (Fixnum) to Comparable (2.4.0-preview2)
From:
zomg.tim@...
Date:
2016-10-22 10:48:03 UTC
List:
ruby-core #77713
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 #<Thread:0x000000014afaf0 run> (TypeError)
from ../test5.rb:16:in `block in <main>'
from ../test5.rb:14:in `each'
from ../test5.rb:14:in `<main>'
~~~
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: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>