Why is sqrt() not a method on Numeric?
In Ruby everything is an object. That's why I don't understand why we have the Math module. It seems to me that most (all?) of 开发者_运维技巧the functions in the Math module should have been methods on the numeric types like Integer, Float and so on.
E.g. instead of
Math.sqrt(5)
it would make more sense to have
5.sqrt
The same goes for sin
, cos
, tan
, log10
and so on.
Does anyone know why all these functions ended up in the Math module?
I don't know the early history of Ruby, but I have a feeling the Math module was modelled after the C <math.h> header. It is an odd duck in the Ruby standard library though.
But, it's Ruby! So you can always bust out the monkey patching!
class Float
def sqrt; Math.sqrt(self); end
def sin; Math.sin(self); end
def cos; Math.cos(self); end
def tan; Math.tan(self); end
def log10; Math.log10(self); end
end
To expand on Michael's answer, there's no need to define all those methods by hand. Note that I explicitly skip the two Math methods that take two arguments.
class Numeric
(Math.methods - Module.methods - ["hypot", "ldexp"]).each do |method|
define_method method do
Math.send method, self
end
end
end
puts 25.sqrt
puts 100.log10
Output:
5.0
2.0
In regards to exactly why those methods are not included in Numeric
already, I'm really not sure of a good reason. I don't think namespace pollution as Andrew mentioned is particularly a risk in the Numeric
class; Michael is probably on the right track with historic carryover.
I've rewritten Mark's answer to be more concise, and not require removing hypot
and ldexp
, since I'm using this approach myself.
class Numeric
Math.methods(false).each do |method|
define_method method do |*args|
Math.send(method, self, *args)
end
end
end
>> 3.hypot(4)
=> 5.0
>> Math::PI.sqrt
=> 1.7724538509055159
>> 10.log10
=> 1
When talking about modules and namespaces, Programming Ruby (the pickaxe) gave an example of an object with both mathematical functions mixed in, and functions to do with morality mixed in, so that it could calculate how many angels can dance on the head of a pin. It then noted that without proper namespacing, sin
could be an ambiguous term.
So maybe it's about namespace pollution.
5 ** 0.5
demonstrates that ruby's exponentiation operator can handle square roots directly, as for log, sin etc, these make more sense to me as global functions rather than methods: their origins are in mathematics and are not closely related to any one float instance.
精彩评论