Automatic class conversion / function overloading

Hi! Rather new to ruby, and I'm not quite sure where to look for the
information I want.

In C++ it's possible to have function overloading... ie

void foo(int a) and void foo(rational a)

Do I have to resort to

def foo(a)
   case a
      when Fixnum ...
      when Rational ...
   end
end

or is there any other way to do this?

....or perhaps a way to do the functional equivalent of C++s

class rational
{
   rational(int a) { ... } // conversion constructor
}

void foo(rational a) should now work for foo(3)

···

--
Eld på åren og sol på eng gjer mannen fegen og fjåg. [Jøtul] /o)\
<demo> 2004 Tore Halvorsen || Cell: +052 0553034554 \(o/

"Tore Halvorsen" <torehalv@jaguar.stud.ntnu.no> schrieb im Newsbeitrag
news:slrnckldim.k7o.torehalv@jaguar.stud.ntnu.no...

Hi! Rather new to ruby, and I'm not quite sure where to look for the
information I want.

In C++ it's possible to have function overloading... ie

void foo(int a) and void foo(rational a)

Do I have to resort to

def foo(a)
   case a
      when Fixnum ...
      when Rational ...
   end
end

or is there any other way to do this?

...or perhaps a way to do the functional equivalent of C++s

class rational
{
   rational(int a) { ... } // conversion constructor
}

void foo(rational a) should now work for foo(3)

You can't do that directly. However have a look at

Regards

    robert

Essentially it's what you've written. However, you'll find that in more
cases than you expect you don't actually do it. As long as the objects
passed in respond to the same methods, you can just invoke them without
caring what the class is; there is no need for them to be inherited from
some common superclass as would be the case in C++.

As an example:

def foo(logger)
  logger << "hello world\n"
end

This works whether logger is a File, a String, or an Array (even though
their common ancestors are Object and Kernel, which don't have a <<
operator). There's no need to write

def foo(logger)
  case logger
  when File ...
  when String ...
  when Array ...
  end
end

It doesn't work if logger is a Fixnum, but then, it doesn't make sense to
append a log string to a Fixnum anyway.

Have a look through Ruby's built-in library. For example, in 'expect.rb'
you'll see several cases where a function can be called either with a hash
or a string as an argument, and it behaves differently in those cases.

Actually, you're often more interested in what methods an object responds
to, rather than its class. In the logger example you're more likely to have

  logger.flush if logger.respond_to?(:flush)

rather than

  case logger
  when File, IO
    logger.flush
  end

You're basically assuming a convention that an IO-like object has methods
"<<" to append and "flush" to flush (if it can be flushed). Such conventions
seem to work well in practice. If you came across an object which didn't,
you could add a "<<" method to that object or to its class to do what you
want, or make a wrapper object which normalises the method call interface.

Exception handling is another way to avoid explicit tests for class:

  begin
    logger.flush
  rescue NoMethodError
  end

Regards,

Brian.

···

On Fri, Sep 17, 2004 at 07:04:53PM +0900, Tore Halvorsen wrote:

In C++ it's possible to have function overloading... ie

void foo(int a) and void foo(rational a)

Do I have to resort to

def foo(a)
   case a
      when Fixnum ...
      when Rational ...
   end
end

or is there any other way to do this?

void foo(int a) and void foo(rational a)

Do I have to resort to

def foo(a)
   case a
      when Fixnum ...
      when Rational ...
   end
end

As I understand it, the idiom in ruby would be to, where possible,
ignore the difference and assume that both a (rational) and a (fixnum)
respond to the methods you want to call on them ...

def increment(a) # a could be a Fixnum, Integer, Rational, Bignum
whatever
    a += 1 # Rely on the fact that they all respond to the method +
end

If classes might have different methods then you could redefine them
so that they all have the same method:

class Integer
alias :newnamefor :oldmethod
end

Hope that helps

Tom

You can't do that directly. However have a look at
http://www.rubygarden.org/ruby?MethodOverloading

That's very interesting. A little aliasing magic? Hmm... (see gears working
inside tommy's head)

Actually I'm more interested in overloading based on arity, rather then class.

···

On Friday 17 September 2004 07:44 am, Robert Klemme wrote:

On Friday 17 September 2004 07:52 am, Brian Candler wrote:

Actually, you're often more interested in what methods an object responds
to, rather than its class. In the logger example you're more likely to have

logger.flush if logger.respond_to?(:flush)

Exactly! This is a good practice to get in too.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

Brian Candler wrote:
[...]

Essentially it's what you've written. However, you'll find that in
more cases than you expect you don't actually do it. As long as the
objects passed in respond to the same methods, you can just invoke
them without caring what the class is; there is no need for them to
be inherited from some common superclass as would be the case in C++.

[...]

Thanks for helpfull info, but still...

I agree, but when trying to make a class for rational numbers, I
wanted to be able to multiply both rational and fixnums to it.

class Rational
  attr_reader :u, :d #up, down
  def *(other)
    Rational.new(self.u * other.u, self.d * other.d)
  end
end

This obviously doesn't automatically work when passing a Fixnum as the
argument. The C++ way is to create an automatic converter - or
function overload. So the ruby way here would be:

class Rational
  attr_reader :u, :d
  def *(o)
    case other
      when Rational
        other = o
      when Fixnum
        other = Rational.new(o, 1)
    end
    Rational.new(self.u * other.u, self.d * other.d)
  end
end

?

I need a ruby-idioms book :slight_smile:

···

--
Eld på åren og sol på eng gjer mannen fegen og fjåg. [Jøtul] /o)\
<demo> 2004 Tore Halvorsen || Cell: +052 0553034554 \(o/

trans. (T. Onoma) wrote:

Actually I'm more interested in overloading based on arity, rather
then class.

I've done a simply library that allows overloading on anything that can
be expressed as a lambda. It also does proper scoring so you can have an
Array and Enumerable version of a method and the right one will get called.

Of course there's not a big difference between this and the common case
when construct except that having the dispatchers outside of the method
lets you easily add new ones from the outside.

I've pasted it to http://www.codepaste.org/view/paste/150 -- maybe it will be useful to you.

Regards,
Florian Gross

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200409170811.02268.transami@runbox.com...

> Actually, you're often more interested in what methods an object

responds

> to, rather than its class. In the logger example you're more likely to

have

>
> logger.flush if logger.respond_to?(:flush)

Exactly! This is a good practice to get in too.

Not generally. In the light of duck typing you normally just invoke
methods and get bitten by an exception. Of course, if you plan to use
objects as arguments that support or don't support #flush that might be
the only feasible approach.

Kind regards

    robert

···

On Friday 17 September 2004 07:52 am, Brian Candler wrote:

Perhaps. But (as others have noted) there isn't a single unique ruby
way. My ruby way would be more like

class Rational
    attr_reader :u, :d
    def *(other)
        other = Rational.new(other, 1) if other.is_a? Fixnum
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

     But as you can see, I even use the old salient-structure
indentation rules. Depending on the situation, I might also write:

class Fixnum
    def to_rational
         Rational.new(self,1)
         end
    end

class Rational
    attr_reader :u, :d
    def *(other)
        other = other.to_rational unless other.is_a? Rational
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

Which would permit types other than Fixnum, provided they implemented
to_rational. Taking this to its logical conclusion I would surely then
rewrite it as:

class Fixnum
    def to_rational
         Rational.new(self,1)
         end
    end

class Rational
    attr_reader :u, :d
    def to_rational
        self
        end
    def *(other)
        other = other.to_rational
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

...which eliminates all class testing and is fairly easily extensible.
But of course others might have different solutions.

-- MarkusQ

···

On Fri, 2004-09-17 at 06:44, Tore Halvorsen wrote:

So the ruby way here would be:

class Rational
  attr_reader :u, :d
  def *(o)
    case other
      when Rational
        other = o
      when Fixnum
        other = Rational.new(o, 1)
    end
    Rational.new(self.u * other.u, self.d * other.d)
  end
end

1) There is a Rational class in Ruby already.

2) Look at #coerce (I believe it's either Fixnum#coerce or
Numeric#coerce). This will allow you to coerce numbers into different
forms.

-austin

···

On Fri, 17 Sep 2004 22:44:46 +0900, Tore Halvorsen <torehalv@jaguar.stud.ntnu.no> wrote:

I agree, but when trying to make a class for rational numbers, I
wanted to be able to multiply both rational and fixnums to it.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca
: as of this email, I have [ 6 ] Gmail invitations

Cool. I'll have a look at it.

BTW, is there anyway to download codepastes? Maybe I'm missing something
obvious, but I've yet to figure out a simple way to "grab" the code and bring
it down to my machine.

Thanx,
T.

···

On Friday 17 September 2004 08:19 am, Florian Gross wrote:

trans. (T. Onoma) wrote:
> Actually I'm more interested in overloading based on arity, rather
> then class.

I've done a simply library that allows overloading on anything that can
be expressed as a lambda. It also does proper scoring so you can have an
Array and Enumerable version of a method and the right one will get called.

Of course there's not a big difference between this and the common case
when construct except that having the dispatchers outside of the method
lets you easily add new ones from the outside.

I've pasted it to http://www.codepaste.org/view/paste/150 -- maybe it
will be useful to you.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

"Markus" <markus@reality.com> schrieb im Newsbeitrag
news:1095431743.19139.114.camel@lapdog.reality.com...

···

On Fri, 2004-09-17 at 06:44, Tore Halvorsen wrote:

> So the ruby way here would be:
>
> class Rational
> attr_reader :u, :d
> def *(o)
> case other
> when Rational
> other = o
> when Fixnum
> other = Rational.new(o, 1)
> end
> Rational.new(self.u * other.u, self.d * other.d)
> end
> end

Perhaps. But (as others have noted) there isn't a single unique ruby
way. My ruby way would be more like

class Rational
    attr_reader :u, :d
    def *(other)
        other = Rational.new(other, 1) if other.is_a? Fixnum
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

     But as you can see, I even use the old salient-structure
indentation rules. Depending on the situation, I might also write:

class Fixnum
    def to_rational
         Rational.new(self,1)
         end
    end

class Rational
    attr_reader :u, :d
    def *(other)
        other = other.to_rational unless other.is_a? Rational
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

Which would permit types other than Fixnum, provided they implemented
to_rational. Taking this to its logical conclusion I would surely then
rewrite it as:

class Fixnum
    def to_rational
         Rational.new(self,1)
         end
    end

class Rational
    attr_reader :u, :d
    def to_rational
        self
        end
    def *(other)
        other = other.to_rational
        Rational.new(self.u * other.u, self.d * other.d)
        end
    end

..which eliminates all class testing and is fairly easily extensible.
But of course others might have different solutions.

-- MarkusQ

Btw: you know that there are classes Rational, Complex etc. already, do
you?

    robert

Austin Ziegler wrote:

1) There is a Rational class in Ruby already.

Figured as much, but I wanted to know how the mechanism is done in
ruby.

2) Look at #coerce (I believe it's either Fixnum#coerce or
Numeric#coerce). This will allow you to coerce numbers into different
forms.

I'll take a look at that. Thanks :slight_smile:

···

--
Eld på åren og sol på eng gjer mannen fegen og fjåg. [Jøtul] /o)\
<demo> 2004 Tore Halvorsen || Cell: +052 0553034554 \(o/

Markus wrote:

Which would permit types other than Fixnum, provided they implemented
to_rational. Taking this to its logical conclusion I would surely then
rewrite it as:

class Fixnum
   def to_rational
        Rational.new(self,1)
        end
   end

class Rational
   attr_reader :u, :d
   def to_rational
       self
       end
   def *(other)
       other = other.to_rational
       Rational.new(self.u * other.u, self.d * other.d)
       end
   end

..which eliminates all class testing and is fairly easily extensible.
But of course others might have different solutions.

Thanks :slight_smile:

.. o O (You learn something every day)

···

--
Eld på åren og sol på eng gjer mannen fegen og fjåg. [Jøtul] /o)\
<demo> 2004 Tore Halvorsen || Cell: +052 0553034554 \(o/

"trans. (T. Onoma)" <transami@runbox.com> schrieb im Newsbeitrag
news:200409170850.53615.transami@runbox.com...

BTW, is there anyway to download codepastes? Maybe I'm missing something
obvious, but I've yet to figure out a simple way to "grab" the code and

bring

it down to my machine.

When using nopaste there is a link for downloading. Example:

http://rafb.net/paste/results/tAgl2817.html

    robert

> > So the ruby way here would be:...
> >
> My ruby way would be more like...
>
>

Btw: you know that there are classes Rational, Complex etc. already, do
you?

     Yes. But it's a convenient context for discussing the real issues
(why overloading isn't as needed in ruby, how duck typing reduces the
need for class-tests, etc.) since it's reasonable to assume that
everyone knows what the semantics _should_be_ and thus we can focus on
how they are best implemented.

     -- MarkusQ

If you want to see an example of Ruby idiom in practice, just see
/usr/local/lib/ruby/1.8/rational.rb (or wherever it is on your system)

The stuff with #coerce I never 100% understood, but then I've never had to
use it for any of my own classes. I've only ever seen it used for the
various different ways of representing numbers.

Regards,

Brian.

···

On Sat, Sep 18, 2004 at 12:17:57AM +0900, Markus wrote:

> Btw: you know that there are classes Rational, Complex etc. already, do
> you?

     Yes. But it's a convenient context for discussing the real issues
(why overloading isn't as needed in ruby, how duck typing reduces the
need for class-tests, etc.) since it's reasonable to assume that
everyone knows what the semantics _should_be_ and thus we can focus on
how they are best implemented.

"Brian Candler" <B.Candler@pobox.com> schrieb im Newsbeitrag news:20040918162110.GA1146@uk.tiscali.com...

> Btw: you know that there are classes Rational, Complex etc. already, do
> you?

     Yes. But it's a convenient context for discussing the real issues
(why overloading isn't as needed in ruby, how duck typing reduces the
need for class-tests, etc.) since it's reasonable to assume that
everyone knows what the semantics _should_be_ and thus we can focus on
how they are best implemented.

Ah, I see.

If you want to see an example of Ruby idiom in practice, just see
/usr/local/lib/ruby/1.8/rational.rb (or wherever it is on your system)

The stuff with #coerce I never 100% understood, but then I've never had to
use it for any of my own classes. I've only ever seen it used for the
various different ways of representing numbers.

I saw a really nice explanation of all these Ruby protocols (#coerce, #to_str etc.) - I don't exactly remember where it was, could be in Pickaxe II.

Kind regards

    robert

···

On Sat, Sep 18, 2004 at 12:17:57AM +0900, Markus wrote: