Overloaded constructors in Ruby


#1

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 H.
removed_email_address@domain.invalid


#2

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


#3

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


#4

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.


#5

In article removed_email_address@domain.invalid,
Kyle H. removed_email_address@domain.invalid wrote:

   this(x, y, strength, 0, 0)

(ArgumentError)
@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


#6

Kyle H. wrote:

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)


#7

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