Forum: Ruby-core mathn/rational destroys Fixnum#/, Fixnum#quo and Bignum#/, Bignum#quo

Posted by marcandre (Marc-Andre Lafortune) (Guest)
on 2012-11-16 18:40
(Received via mailing list)
Issue #2121 has been updated by marcandre (Marc-Andre Lafortune).

Description updated
Category set to lib

It does create some problems in real apps (e.g. 
https://github.com/rails/rails/pull/8222 )

The problem is compatibility. I always thought that it was the intent of 
`mathn` to change the semantics of `/` so that the same operations would 
have different meanings. For example `Matrix[[1]] / 2` returns different 
results depending on the presence of `mathn` or not.

Avoiding the problem is trivial: when you mean "division with truncation 
to integer", use `Integer#div` instead of `Integer#/`.

`div` has the advantage of being crystal clear, since `foo.div(bar)` 
always truncates down to an integer, while `foo / bar` can return any of 
Integer, Rational, Float, BigDecimal, Complex, Matrix, Vector, etc., 
depending on the classes of foo, bar (and if mathn is loaded or not)

What I'm trying to say is that, given the choices made in the past, 
using `/` instead of `div` can be seen as a user mistake, although it 
clearly is an easy one to make. Ideally, library/framework authors would 
be aware of this and reserve `Integer#/` for mathematical libraries and 
use `div` where appropriate.

I don't see how we can change the current behavior, but adding a note in 
the doc for `Integer#/` about this could not hurt.

----------------------------------------
Bug #2121: mathn/rational destroys Fixnum#/, Fixnum#quo and Bignum#/, 
Bignum#quo
https://bugs.ruby-lang.org/issues/2121#change-32984

Author: headius (Charles Nutter)
Status: Assigned
Priority: Normal
Assignee: keiju (Keiju Ishitsuka)
Category: lib
Target version:
ruby -v: Any 1.8.6 or higher


=begin
 I've known this for a while, but only now realized this is actually a 
terrible bug.

 The mathn library replaces Fixnum#/ and Bignum#/ causing them to return 
a different value. When the result of a division is not an integral 
value, the default versions will return 0. I can think of many 
algorithms that would use this expectation, and most other languages 
will not upconvert integral numeric types to floating-point or 
fractional types without explicit consent by the programmer.

 When requiring 'mathn', Fixnum#/ and Bignum#/ are replaced with 
versions that return a fractional value ('quo') causing a core math 
operator to return not just a different type, but *a different value*.

 No core library should be allowed to modify the return value of core 
numeric operators, or else those operators are worthless; you can't rely 
on them to return a specific value *ever* since someone else could 
require 'mathn' or 'rational'.

 Note also that 'rational' destroys Fixnum#quo and Bignum#quo. This is 
also a bug that should be fixed, though it is less dangerous because 
they're not commonly-used operators.

 The following code should not fail; Fixnum#/ should never return a 
value of a different magnitude based on which libraries are loaded:

 {{{
 require 'test/unit'

 class TestFixnumMath < Test::Unit::TestCase
   # 0 to ensure it runs first, for illustration purposes
   def test_0_without_mathn
     assert_equal 0, 1/3
   end

   def test_with_mathn
     require 'mathn'
     assert_equal 0, 1/3
   end
 end
 }}}

 But it does fail:

 {{{
 ~/projects/jruby ➔ ruby test_fixnum_math.rb
 Loaded suite test_fixnum_math
 Started
 .F
 Finished in 0.016003 seconds.

   1) Failure:
 test_with_mathn(TestFixnumMath) [test_fixnum_math.rb:11]:
 <0> expected but was
 <1/3>.

 2 tests, 2 assertions, 1 failures, 0 errors
 }}}
=end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.