[ruby-core:75321] [Ruby trunk Bug#12337] inconsistency between Fixnum#coerce and Bignum#coerce

From: akr@...
Date: 2016-05-03 09:10:39 UTC
List: ruby-core #75321
Issue #12337 has been updated by Akira Tanaka.

File int-coerce.patch added

I made a patch to fix this problem.

This implements bignum.coerce(float) to be [float, float] and
fixnum.coerce(bignum) to be [bignum, bignum].

```
% ./ruby -e '    
fixnum = 3
bignum = 2**70
float = 5.0
[fixnum, bignum, float].each {|n1|
  [fixnum, bignum, float].each {|n2|
    result = n1.coerce(n2).map {|n| n.class } rescue $!.class
    puts "#{n1.class}.coerce(#{n2.class}) => #{result.inspect}"
  }
}'
Fixnum.coerce(Fixnum) => [Fixnum, Fixnum]
Fixnum.coerce(Bignum) => [Bignum, Bignum]
Fixnum.coerce(Float) => [Float, Float]
Bignum.coerce(Fixnum) => [Bignum, Bignum]
Bignum.coerce(Bignum) => [Bignum, Bignum]
Bignum.coerce(Float) => [Float, Float]
Float.coerce(Fixnum) => [Float, Float]
Float.coerce(Bignum) => [Float, Float]
Float.coerce(Float) => [Float, Float]
```

Note that a released version works as follows.

```
% ruby-2.3.1 -e '
fixnum = 3
bignum = 2**70
float = 5.0
[fixnum, bignum, float].each {|n1|
  [fixnum, bignum, float].each {|n2|
    result = n1.coerce(n2).map {|n| n.class } rescue $!.class
    puts "#{n1.class}.coerce(#{n2.class}) => #{result.inspect}"
  }
}'
Fixnum.coerce(Fixnum) => [Fixnum, Fixnum]
Fixnum.coerce(Bignum) => [Float, Float]
Fixnum.coerce(Float) => [Float, Float]
Bignum.coerce(Fixnum) => [Bignum, Bignum]
Bignum.coerce(Bignum) => [Bignum, Bignum]
Bignum.coerce(Float) => TypeError
Float.coerce(Fixnum) => [Float, Float]
Float.coerce(Bignum) => [Float, Float]
Float.coerce(Float) => [Float, Float]
```



----------------------------------------
Bug #12337: inconsistency between Fixnum#coerce and Bignum#coerce
https://bugs.ruby-lang.org/issues/12337#change-58449

* Author: Akira Tanaka
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: ruby 2.4.0dev (2016-05-01 trunk 54866) [x86_64-linux]
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
I found 1.coerce(2.0) is [2.0, 1.0] but
(2**100).coerce(2.0) raises TypeError

```
% ./ruby -ve 'p 1.coerce(2.0)'       
ruby 2.4.0dev (2016-05-01 trunk 54866) [x86_64-linux]
[2.0, 1.0]
% ./ruby -ve 'p (2**100).coerce(2.0)'
ruby 2.4.0dev (2016-05-01 trunk 54866) [x86_64-linux]
-e:1:in `coerce': can't coerce Float to Bignum (TypeError)
	from -e:1:in `<main>'
```

This is a documented behavior.

```
% ri Bignum.coerce|cat
= Bignum.coerce

(from ruby core)
------------------------------------------------------------------------------
  big.coerce(numeric)  ->  array

------------------------------------------------------------------------------

Returns an array with both a numeric and a big represented as Bignum objects.

This is achieved by converting numeric to a Bignum.

A TypeError is raised if the numeric is not a Fixnum or Bignum type.

  (0x3FFFFFFFFFFFFFFF+1).coerce(42)   #=> [42, 4611686018427387904]
```

But I think this is bad bahavior.
Fixnum and Bignum should work seamlessly.

For example, this exposes the platform is 32-bit or 64-bit.
2**40 is Fixnum on 32-bit environment and Bignum on 64-bit environment.
So, (2**40).coerce(2.0) behaves differently: returns an array on 64-bit and
raises TypeError on 32-bit platform.

```
32bit-platform% ./ruby -ve 'p (2**40).coerce(2.0)'
ruby 2.4.0dev (2016-05-01 trunk 54866) [x86_64-linux]
[2.0, 1099511627776.0]

64bit-platform% ./ruby -ve 'p (2**40).coerce(2.0)'
ruby 2.4.0dev (2016-05-01 trunk 54864) [i686-linux]
-e:1:in `coerce': can't coerce Float to Bignum (TypeError)
	from -e:1:in `<main>'
```

I think the behavior of Bignum#coerce should be changed
to match Fixnum#coerce (actually defined at Numeric).


---Files--------------------------------
int-coerce.patch (2.37 KB)


-- 
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>

In This Thread

Prev Next