Overloaded constructors in Ruby

I have a class that I want to have a number of overloaded constructors for.

I tried doing something like this:

class GravPoint
    def initialize()
        this(0, 0, 0, 0, 0)
    end

    def initialize(x, y, strength)
        this(x, y, strength, 0, 0)
    end

    def initialize(x, y, strength, ctime, life)
        @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
    end
end

When I then run GravPoint.new() I get the following error:

GravPoint.rb:23:in `initialize': wrong number of arguments (0 for 5)
(ArgumentError)

I think I understand the error, it's expecting 5 arguments (based on the
last constructor) but I don't the "Ruby" way to set this up. What am I
missing?

I was able to get this to work, but was hoping that I could do it in a
format closer to the above to make it a little more flexible to use.

class GravPoint
    def initialize(x = 0, y = 0, strength = 0, ctime = 0, life = 0 )
        @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
    end
end

Kyle Heon
kheon@comcast.net

i believe the way to do it is to use names parameters and/or default
values.

Kyle Heon wrote:

I think I understand the error, it's expecting 5 arguments (based on the
last constructor) but I don't the "Ruby" way to set this up. What am I
missing?

I was able to get this to work, but was hoping that I could do it in a
format closer to the above to make it a little more flexible to use.

class GravPoint
    def initialize(x = 0, y = 0, strength = 0, ctime = 0, life = 0 )
        @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
    end
end

Actually, defining default values for arguments is a very "Ruby" way of handling this case. If the arguments have sensible default values, then I'd argue that it's the best solution. You could also use a hash to simulate named parameters if that's what floats your boat. Another very "Ruby" thing to do is to define multiple constructors with different names.

Something I've done is to define a "basic" constructor and then define one or more methods that modify the basic instance. For example, suppose you have two kinds of rectangles, a regular square-cornered rectangle and a rectangle with rounded corners. The difference between the two rectangles is that the rounded rectangle needs an extra 2 numbers to define the radii of the ovals that make up the corner. If you want a plain rectangle just call "new". If you want a rounded rectangle, modify the newly-constructed instance by calling "rounded" on it.

class Rectangle
    def initialize(width, height)
       @width, @height = width, height
    end

    def rounded(rx, ry)
       @rx, @ry = rx, ry
    end
end

rect = Rectangle.new(20, 30)
round_rect = Rectangle.new(20, 30).rounded(2, 3)

Timothy makes good points, but just so you understand how to write
alernate constructors for Ruby there are two weys.

First one can define alternate constructors:

  class GravPoint

    # however you wish to name them...

    def self.new_zero()
        new(0, 0, 0, 0, 0)
    end

    def self.new_lite(x, y, strength)
        new(x, y, strength, 0, 0)
    end

    def initialize(x, y, strength, ctime, life)
        @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
    end

  end

The other way is the use variable parameters. Something like:

     def initialize(*args)
        x, y, strength, ctime, life = 0,0,0,0,0
        case args.length
        when 0
          # good just the way it is, skip
        when 3
          x, y, strength = *args
        when 5
          x, y, strength, ctime, life = *args
        else
          raise ArgumentError
        end
        @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
     end

  T.

In article <20051206012149.EF632339CD@beryllium.ruby-lang.org>,

I have a class that I want to have a number of overloaded constructors for.

I tried doing something like this:

class GravPoint
   def initialize()
       this(0, 0, 0, 0, 0)
   end

   def initialize(x, y, strength)
       this(x, y, strength, 0, 0)
   end

   def initialize(x, y, strength, ctime, life)
       @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
   end
end

When I then run GravPoint.new() I get the following error:

GravPoint.rb:23:in `initialize': wrong number of arguments (0 for 5)
(ArgumentError)

I think I understand the error, it's expecting 5 arguments (based on the
last constructor) but I don't the "Ruby" way to set this up. What am I
missing?

I was able to get this to work, but was hoping that I could do it in a
format closer to the above to make it a little more flexible to use.

class GravPoint
   def initialize(x = 0, y = 0, strength = 0, ctime = 0, life = 0 )
       @x, @y, @strength, @ctime, @life = x, y, strength, ctime, life
   end

     def GravPoint.from_x_y_strength(x,y,strength)
       new(x,y,strength)
     end

end

gp = GravPoint.new #matches your first constructor
gp1= GravPoint.from_x_y_strength 5.5,4.2,254 #matches your 2nd c'tor
gp3= GravPoint.new(1,2,3,4,5) #matches your last c'tor

Phil

···

Kyle Heon <kheon@comcast.net> wrote:

http://www.rubygarden.org/ruby?MethodOverloading

Hi!

I guess you forgot a line, right?

class Rectangle
    def initialize(width, height)
       @width, @height = width, height
    end

    def rounded(rx, ry)
       @rx, @ry = rx, ry
       self #<-FORGOTTEN
    end
end

Sam