This is a journal entry about Ruby and it's kinda long, so move along now if you aren't interested.
Specifically, this is a response to Dave Cross' article "Overloading" on perl.com, a problem I have with Dave's code and how Ruby is just better at OO. You've been warned twice now. Hopefully I won't get kicked off of use.perl or anything...
My first *major* issue is with the fact that Dave returns undef in the event of a failure when creating a new Fraction object (except in one case, where it croaks).  Why not croak on the spot for all failures?  Dave's approach could cause great confusion, forcing me to track down "can't call method on 'undef'" error messages later on.  I won't be able to tell right  away if the constructor failed or if the Fraction object was undef'd somewhere later on accidentally.  Why not at least give me the chance to wrap the constructor in an eval so I can trap that error if I'm so inclinded?  As it is I'll probably be stepping into the debugger at some point, or I'll be forced to write extra tests to account for this possibility.  Blech.
Ok, on to a Ruby version of the code. Let's start with the base class:
UNIVERSAL::isa syntax is an eyesore IMO.  In addition, it's slightly less code.
Second, while I can't declare a type for the parameters (hey, this ain't Java, ok? - but see below), I can give them a name and a default value. This provides an extra advantage over the Perl equivalent in that I can never pass more than two arguments without causing an error.
Third, because everything in Ruby is an object, and all objects have a type, we can use the kind_of? method to test the actual type of each argument rather than resorting to regular expressions, which is clunky. It works in Dave's code, but in general I think that approach is prone to error.
On to the overloading.  Dave provides an "add" method, then overloads the "+" operator.  Here's the Ruby equivalent:
While Ruby doesn't include any built-in mechanism for overloading, there *is* a package on the RAA called "overload" (go figure) written by Nobu Nakada that allows you to achieve the same effect. Consider:
   def initialize(x)
      # ...
   end
   overload(:initialize,Fraction)
   def initialize(x,y)
      # ...
   end
   overload(:initialize,Fixnum,Fixnum)
end
# Now I can do this ...
a = Fraction.new
b = Fraction.new(a)
c = Fraction.new(1,2)
# ... and Ruby will call the appropriate constructor
There. My Ruby proselytizing is done for the day. Don't kill me.
 
class Fraction
 
    def +(n)
        return n.add_fraction(self)
    end
 
    def add_fraction(n)
        return Fraction.new((@num * n.den) + (n.num * @den),
                                                                @den * n.den)
    end
 
    def add_string(str)
        str =~  /(\d+)\/(\d+)/ or
            raise ArgumentError "Can't add '" + str + "' to " +
                self.to_str + ": Badly formed string"
        return Fraction.new($1.to_i, $2.to_i)
    end
 
    def add_fixnum(n)
        return self + Fraction.new(n.to_i, 1)
    end
end
 
class Fixnum
    def add_fraction(n)
        n.add_fixnum(self)
    end
end
 
class String
    def add_fraction(n)
        n.add_string(self)
    end
end
 
class Object
    def add_fraction(n)
        raise ArgumentError, "Can't add a " + self.class.to_s + " to a Fraction"
    end
end
  Re:Hmmm
djberg96 on 2003-07-24T15:31:25
Hmm..probably. Perhaps I was being too faithful to Dave's code (someone else on IRC already said something similar). In Ruby, as in Perl, TMTOWTDI.
My first *major* issue is with the fact that Dave returns undef in the event of a failure when creating a new Fraction object (except in one case, where it croaks).
Actually, returning "undef" from the constructor is a vital part of the way the module works when it comes to constant overloading. It's the one instance of using "croak" that is a bug.