Feature #18179
openAdd Math methods to Numeric
Description
Hi, I wanted to get thoughts on adding class methods from Math
as instance methods on Numeric
.
x.sqrt # vs Math.sqrt(x)
x.log # vs Math.log(x)
Rust takes this approach and it (subjectively) feels more intuitive/object-oriented. It also seems more consistent with methods like x.abs
.
Updated by duerst (Martin Dürst) about 3 years ago
I support this. x.sqrt
is indeed more object-oriented that Math.sqrt x
. In an earlier discussion, it was pointed out that for Mathematicians, sqrt(x)
is more natural than x.sqrt
. Mathematicians can still use that notation, but also having the object-oriented notation in Ruby would indeed be great.
Updated by mrkn (Kenta Murata) about 3 years ago
I'm negative to this proposal. I don't think Math.sqrt
is the behavior or the property of a Numeric object. It is the positive square root function that maps from/to the set of non-negative real numbers.
If we introduce Numeric#sqrt
, we should expand its domain to negative numbers and Complex numbers. Also, it is better to consider other kinds of numbers, such as Quaternion.
Updated by mame (Yusuke Endoh) almost 3 years ago
- Has duplicate Feature #18477: Float#sqrt and Integer#sqrt added
Updated by duerst (Martin Dürst) over 2 years ago
mrkn (Kenta Murata) wrote in #note-2:
I'm negative to this proposal. I don't think
Math.sqrt
is the behavior or the property of a Numeric object. It is the positive square root function that maps from/to the set of non-negative real numbers.
This is how Mathematicians think, and we don't want to take this possibility away from them. But Ruby is mainly for Ruby programmers. And most Ruby programmers may not think like Mathematicians. Ruby programmers should be able to use Ruby the Ruby way, even for such functionality.
For example, if I have an array a
, and want to create an array of square roots from it, currently I have to write:
a.map { |n| Math.sqrt n }
With this proposal, it would be possible to write:
a.map(&:sqrt)
This expresses the intent (map the squareroot function) in a much more concise and functional way.
If we introduce
Numeric#sqrt
, we should expand its domain to negative numbers and Complex numbers. Also, it is better to consider other kinds of numbers, such as Quaternion.
Now that Complex is built-in, producing an error on Math.sqrt(-2)
indeed doesn't look good. That's independent of this proposal, but it could be implemented together.
Updated by Hanmac (Hans Mackowiak) over 2 years ago
For the Complex Problem, maybe add an optional parameter like :raise_on_complex
or something so when you try:
(-2).sqrt
it returns complex,
but (-2).sqrt(raise_on_complex: true)
makes the old Exception?
Updated by Eregon (Benoit Daloze) over 2 years ago
Out of all Math methods:
acos, acosh, asin, asinh, atan, atan2, atanh, cbrt, cos, cosh, erf,
erfc, exp, frexp, gamma, hypot, ldexp, lgamma, log, log10, log2, sin,
sinh, sqrt, tan, tanh
I think for me only sqrt would maybe feel natural as num.sqrt
.
We already have Integer.sqrt
(but no #sqrt
), so that might be confusing.
Math
always deals with Float numbers, so that's consistent, but having it on numeric is less clear, should 5.sqrt
be 2
(like Integer.sqrt
) or 2.23606797749979
(like Math.sqrt
)?
It's also not clear what should be Rational(a, b).sqrt
, a Float, a Rational? The point of Rational is to be exact, converting to Float somewhat implicitly doesn't seem good.
At least I feel num.sin
, num.cos
, num.acos
, num.cosh
, etc, all look weird.
I would think many people would generally agree to that, but maybe I'm wrong.
Math.hypot
seems also a good example why that should not be an instance method, because it takes two arguments as equal, there is no "receiver" and "operand" distinction.
Moving these methods to Float
(instead of Numeric
) would at least make it clear they use Float operands and return a Float, and sounds like a better change to me.
That would mean integer.to_f.sqrt
if one wants the Float square root of an integer.
It seems Rust defines most of the Ruby Math methods on f64 (https://doc.rust-lang.org/std/primitive.f64.html) and much less (e.g., no sqrt) on i64 (https://doc.rust-lang.org/std/primitive.i64.html).