Dave Thomas <dave / pragprog.com> wrote in message news:<3EA7FF8F.3080500 / pragprog.com>...
> I'm trying to get to grips with the 'mathn' library. I can see what it 
> _does_, but I'm trying to see why it does it. Is it emulating a mathn 
> library in some other language, or is it simply there to make arithmetic 
> more accurate?

   In math, 7 is an integer.  It is also a rational
number, a real number, and a complex number.  The
mathn library allows 7 to effectively be all of these
by making Float, Fixnum, Bignum, Rational, and Complex
all play nice with one another.  In a program that
requires mathn, we can treat 7 according to its
mathematical properties rather than the properties
of the class hierarchy.  Also, as I've mentioned
before, matrix.rb needs mathn.rb in order to work
properly.

   The OO paradigm is rather alien to the mathematical
mind.  Mathematicians might think of the expression
"3 + 7" in various ways, depending on their background
and what they had for breakfast.  But I'm sure damn
few of them think of it as the object 3 receiving the
method + with an argument of 7 !  So I've been surprised
at how easy it is to write mathematical programs in
ruby.  In fact, ruby is very good at math, even quite
sophisticated math.  Doubters should take a look at
the algebra package in the RAA.

   Ruby's reflective powers and dynamic nature allow
one to get around OO head-scratchers.  For example,
I've been working on a polynomial package (pnom.rb,
coming soon to an RAA near you).  I wanted to allow
anything that represented some sort of complex number
as a coefficient, so I required mathn.  I needed to add
a bunch of methods to the classes representing complex
numbers according to mathn, so that they would play
nice with my new Pnom class. But what if the user
created a Numeric class fitting the bill, for example,
a class QuadRat of quadratic rationals (numbers of the
form a + b*sqrt(c), where a, b, and c are rational),
I wanted the user to be able to use that class too.

   With ruby I was able to rewrite a bunch of methods
in all the appropriate classes without knowing about
classes the user wanted to add in advance.  I also wanted
the package to be well behaved when it was reloaded.
Here is how I handled them:

# make infix operators in Numeric classes play nice with Pnom
PlayNiceWithPnom = {'+'=>'Plus', '*'=>'Mul', '<=>'=>'Spaceship',
  '=='=>'Equal', '<'=>'Less', '>'=>'Greater', '<='=>'LessEqual',
  '>='=>'GreaterEqual'}
PlayNiceWithPnom.each {|key, value|
  eval(%Q% PlayNiceWithPnom#{value} = <<-EOS
alias prePnom_#{value} #{key}
def #{key}(other)
  if defined?(Pnom) and other.kind_of?(Pnom)
    Pnom.new(self) #{key} other
  else
    prePnom_#{value}(other)
  end
end
EOS
%)
}
ObjectSpace.each_object(Class) {|klass|
  if klass.ancestors.include?(Numeric)
    PlayNiceWithPnom.each{|key, value|
      if klass.public_instance_methods.include?(key)
        unless klass.public_instance_methods.include?("prePnom_#{value}")
          eval(%Q%  klass.module_eval(PlayNiceWithPnom#{value})%)
        end
      end
    }
  end
}       

   I shudder to think of trying to accomplish this in Python!

   Regards, Bret