Automatic class conversion / function overloading

Discussion in 'Ruby' started by Tore Halvorsen, Sep 17, 2004.

  1. 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, Sep 17, 2004
    #1
    1. Advertising

  2. "Tore Halvorsen" <> schrieb im Newsbeitrag
    news:...
    > 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
    http://www.rubygarden.org/ruby?MethodOverloading

    Regards

    robert
    Robert Klemme, Sep 17, 2004
    #2
    1. Advertising

  3. 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?


    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.
    Brian Candler, Sep 17, 2004
    #3
  4. On Friday 17 September 2004 07:44 am, Robert Klemme wrote:
    > 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: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.
    / \

    I don't give a damn for a man that can only spell a word one way.
    -Mark Twain
    trans. (T. Onoma), Sep 17, 2004
    #4
  5. 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
    Florian Gross, Sep 17, 2004
    #5
  6. "trans. (T. Onoma)" <> schrieb im Newsbeitrag
    news:...

    > 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.


    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
    Robert Klemme, Sep 17, 2004
    #6
  7. 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.


    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.


    --
    ( o _ カラãƒ
    // trans.
    / \

    I don't give a damn for a man that can only spell a word one way.
    -Mark Twain
    trans. (T. Onoma), Sep 17, 2004
    #7
  8. "trans. (T. Onoma)" <> schrieb im Newsbeitrag
    news:...

    > 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
    Robert Klemme, Sep 17, 2004
    #8
  9. 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 :)

    --
    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, Sep 17, 2004
    #9
  10. Tore Halvorsen

    Markus Guest

    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
    Markus, Sep 17, 2004
    #10
  11. "Markus" <> schrieb im Newsbeitrag
    news:...
    > 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
    Robert Klemme, Sep 17, 2004
    #11
  12. On Fri, 17 Sep 2004 22:44:46 +0900, Tore Halvorsen
    <> 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.


    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
    --
    Austin Ziegler *
    * Alternate:
    : as of this email, I have [ 6 ] Gmail invitations
    Austin Ziegler, Sep 17, 2004
    #12
  13. Tore Halvorsen

    Markus Guest

    > > > 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
    Markus, Sep 17, 2004
    #13
  14. 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 :)

    .. 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/
    Tore Halvorsen, Sep 17, 2004
    #14
  15. 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 :)

    --
    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, Sep 17, 2004
    #15
  16. Tore Halvorsen

    Tom Counsell Guest

    > 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 :eek:ldmethod
    end

    Hope that helps

    Tom
    Tom Counsell, Sep 17, 2004
    #16
  17. 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.


    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.
    Brian Candler, Sep 18, 2004
    #17
  18. "Brian Candler" <> schrieb im Newsbeitrag
    news:...
    > 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.


    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
    Robert Klemme, Sep 19, 2004
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Iyer, Prasad C

    Overloading __init__ & Function overloading

    Iyer, Prasad C, Sep 30, 2005, in forum: Python
    Replies:
    3
    Views:
    6,394
    Fredrik Lundh
    Sep 30, 2005
  2. Fredrik Lundh
    Replies:
    0
    Views:
    437
    Fredrik Lundh
    Sep 30, 2005
  3. Steve Holden
    Replies:
    0
    Views:
    420
    Steve Holden
    Sep 30, 2005
  4. Iyer, Prasad C
    Replies:
    4
    Views:
    570
    John J. Lee
    Sep 30, 2005
  5. Fredrik Lundh
    Replies:
    0
    Views:
    389
    Fredrik Lundh
    Sep 30, 2005
Loading...

Share This Page