tags:

views:

172

answers:

3

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?

+5  A: 

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
Michael Melanson
+2  A: 

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.

Andrew Grimm
That concern applies to duck typing in general, not just the Math functions. I doubt that could be the reason.
KaptajnKold
+4  A: 

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.

Mark Rushakoff
Change that to `define_method(method) do |*args| Math.send(method, self, *args) end`, and there's no longer a need to exclude `hypot` or `ldexp`.
molf
The expression (Math.methods - Module.methods) can also be shortened to just Math.methods(false)
Lars Haugseth