Does Ruby not support multiple "initialize" methods for a cl


#1

Hi,

Q1 - Does Ruby not support multiple “initialize” methods for a class?

Q2 - If no is there a reason for this out of curiosity?

Q3 - What approach is recommended if this constraint does exist?

Cheers
Greg


#2

On 3/20/07, Greg H. removed_email_address@domain.invalid wrote:

Q1 - Does Ruby not support multiple “initialize” methods for a class?

Q2 - If no is there a reason for this out of curiosity?

Q3 - What approach is recommended if this constraint does exist?

I am not sure what you want to achieve here. There is nothing magic
about initialize; it is just a method that is called from new. Maybe
you’re talking of multiple new methods instead of multiple initialize
methods?

new used to be magic; however, the magic has been moved, so these days
new is the same as

def Class.new(*args)
object = allocate
object.initialize(*args)
object
end

with “allocate” being the ‘magic’ method to allocate new objects.
With this, you can easily create multiple new methods, too.

Eivind.


#3

Greg H. wrote:

Hi,

Q1 - Does Ruby not support multiple “initialize” methods for a class?
No.

Q2 - If no is there a reason for this out of curiosity?
Method overloading isn’t supported in general - it’s not just
constructors.

Q3 - What approach is recommended if this constraint does exist?
Default values and varargs, options hashes, or different class
hierarchies. It depends on exactly what you’re trying to achieve. Do
you have an example?


#4

On 3/20/07, Greg H. removed_email_address@domain.invalid wrote:

ruby doesn’t have method overloading. So no multiple initialize methods.

Out of curiosity, why you need multiple initialize methods in a
language like ruby?


#5

I have a class that can be created from a couple of scenarios, and for
each
the initial data to populate the class is different. I was going to
create
two “initialize” methods with their own specific method signature to
cover
off these two scenarios however I guess I will need to perhaps just
create
two separate/normal methods for this. Perhaps then it would be like:

a = Klass.new
a.create_for_scenario_one (…)


#6

Alle martedì 20 marzo 2007, Greg H. ha scritto:

I have a class that can be created from a couple of scenarios, and for each
the initial data to populate the class is different. I was going to create
two “initialize” methods with their own specific method signature to cover
off these two scenarios however I guess I will need to perhaps just create
two separate/normal methods for this. Perhaps then it would be like:

a = Klass.new
a.create_for_scenario_one (…)

You could just declare an initialize method which takes any number of
arguments, then detect the scenario according to the passed argument.
For
example, assuming that in one case the first argument is a number and in
the
second is a string, you could do:

class MyClass

def initialize(*args)
if args[0].is_a? Numeric
#perform initialization in first case
elsif args[0].is_a? String
#perform initialization in second case
else raise TypeError
end
end

end

I hope this helps

Stefano


#7

On 3/20/07, Greg H. removed_email_address@domain.invalid wrote:

I have a class that can be created from a couple of scenarios, and for each
the initial data to populate the class is different. I was going to create
two “initialize” methods with their own specific method signature to cover
off these two scenarios however I guess I will need to perhaps just create
two separate/normal methods for this. Perhaps then it would be like:

a = Klass.new
a.create_for_scenario_one (…)

a = Klass.create_scenario_one(…)
b = Klass.create_scenario_two(…)

That’s the more common idiom in Ruby.

-austin


#8

On 3/20/07, Greg H. removed_email_address@domain.invalid wrote:

Hi,

Q1 - Does Ruby not support multiple “initialize” methods for a class?

Q2 - If no is there a reason for this out of curiosity?

Q3 - What approach is recommended if this constraint does exist?

You could use:

class Invitation
attr_reader :id, :date, :user, :text, :email

def Invitation.withId(id)
return self.new(id)
end

def Invitation.withAll(id, date, user, email, text)
return self.new(id, date, user, email, text)
end

def initialize(id = 0, date = ‘’, user = ‘’, email = ‘’, text = ‘’)
super()
@id = id
@date = date
@email = email
@user = user
@text = text
end
end

then:

invitation = Invitation.withId(1)

or with all params.


#9

On Mar 20, 2007, at 8:26 AM, Greg H. wrote:

I have a class that can be created from a couple of scenarios, and
for each
the initial data to populate the class is different. I was going
to create
two “initialize” methods with their own specific method signature
to cover
off these two scenarios however I guess I will need to perhaps just
create
two separate/normal methods for this. Perhaps then it would be like:

Eivind had your answer. Use new/initialize for one version of your
constructor and then roll your own for the second version:

class Myclass

def self.new2(*args)
object = allocate
object.initialize2(*args)
object
end

def initialize2(*args)
# other initialization code
end
end

Gary W.


#10

On 3/20/07, Stefano C. removed_email_address@domain.invalid wrote:

if args[0].is_a? Numeric
#perform initialization in first case
elsif args[0].is_a? String
#perform initialization in second case
else raise TypeError
end
end

This looks a lot nicer using “case”:

class MyClass

def initialize(*args)
case args0
when Numeric
# …perform numeric initialization
when String
# …perform string initialization
else
raise TypeError
end
end

end

Of course, you can get a lot fancier with your “case” statement using
regular expressions, ranges, multiple matchers per case, etc. The sky’s
the
limit…


#11

On 3/20/07, Emilio T. removed_email_address@domain.invalid wrote:

  return self.new(id, date, user, email, text)

end

then:

invitation = Invitation.withId(1)

or with all params.

Of course the only thing that the withId and withAll (*which in more
normal Ruby style should be with_id and with _all) do is throw an
error if you don’t call them with the right number of parameters.

With the above code you can also write:

Invitation.new
Invitation.new(42)
Invitation.new(99, ‘10/22/2006’)
Invitation.new(35, ‘3/2/1907’, ‘Teddy Roosevelt’)
Invitation.new(67, ‘10/12/2010’, ‘Arthur C. Clarke’,
‘removed_email_address@domain.invalid’)
or
Invitation.new(88, ‘6/6/1945’, ‘Dwight Eisenhower’, ‘removed_email_address@domain.invalid’,
‘I like Ike’)

Any of these work as defaults are provide dor all.

Another approach would be to use a Hash to provide ‘keyword’ arguments.

Invitation.new(:id => 20, :email => ‘removed_email_address@domain.invalid’)

The initialize method would need to pick the hash argument apart.

def initialize(options={})
     # process options and set iv's etc.
end

You could combine this with additional parameters before the hash
parameter.

  • Normal ruby style is to reserve ‘camel case’ for Globals (e.g. class
    and module names) and use underscores as separators in variable names.
    I keep tripping up on that when my old Smalltalk habits kick in.
    It’s not crucial, but when in Ruby do as the Rubyists do.

    Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#12

On Mar 20, 10:42 am, removed_email_address@domain.invalid wrote:

you can use class methods to return objects, as others have mentioned, but it
also extremely easy to do your own function signature matching in ruby

In the interest of ridiculousness, how about using the multi gem for
this? :slight_smile:

require ‘rubygems’
require ‘multi’

class Foo
def initialize(*args)
multi(:init, Integer) { |i|
puts ‘integer used’
# do integer stuff…
}

multi(:init, Float) { |f|
  puts 'float used'
  # do float stuff...
}

init(*args)

end
end


#13

On Mar 20, 10:15 am, “Mat S.” removed_email_address@domain.invalid wrote:

  # do integer stuff...
}

multi(:init, Float) { |f|
  puts 'float used'
  # do float stuff...
}

init(*args)

end
end

Heh, that interface is very similar to Nobu’s overload package. [1]
There’s also Ryan’s strongtyping package for simulating overloaded
methods. [2]

Regards,

Dan

[1] http://www.rubyist.net/~nobu/ruby/overload-0.6.tar.bz2
[2] http://raa.ruby-lang.org/project/strongtyping/

PS - Nobu, you need to update your RAA link for the overload
package. :slight_smile:


#14

On Tue, 20 Mar 2007, Greg H. wrote:

I have a class that can be created from a couple of scenarios, and for each
the initial data to populate the class is different. I was going to create
two “initialize” methods with their own specific method signature to cover
off these two scenarios however I guess I will need to perhaps just create
two separate/normal methods for this. Perhaps then it would be like:

a = Klass.new
a.create_for_scenario_one (…)

you can use class methods to return objects, as others have mentioned,
but it
also extremely easy to do your own function signature matching in ruby

 harp:~ > cat a.rb
 class C
   def initialize *argv, &block
     case argv
     when match(Fixnum)
       initialize_from_int argv[0]
     when match(Fixnum, Float)
       initialize_from_int_float argv[0], argv[1]
     else
       raise ArgumentError, argv.inspect
     end
   end

   def initialize_from_int int
     @int = int
     @float = 0.0
   end

   def initialize_from_int_float int, float
     @int = int
     @float = float
   end

   class Pattern
     def initialize template
       @template = template
     end
     def === objects
       return false unless @template.size == objects.size
       @template.each_with_index do |pat, idx|
         return false unless pat === objects[idx]
       end
       return true
     end
   end
   def match *template
     Pattern.new template
   end
 end

 p C.new(42)
 p C.new(42,42.0)



 harp:~ > ruby a.rb
 #<C:0xb75cff08 @float=0.0, @int=42>
 #<C:0xb75cfcd8 @float=42.0, @int=42>

however, function signature overloading is very confusing when mixed
with
default parameters. most people simply ignore this and live with the
bugs in
c++.

regards.

-a


#15

On 3/20/07, Greg H. removed_email_address@domain.invalid wrote:

Hi,

Q1 - Does Ruby not support multiple “initialize” methods for a class?

Q2 - If no is there a reason for this out of curiosity?

Q3 - What approach is recommended if this constraint does exist?

I have been using the following pattern to implement multiple
constructors for a class. It is only a variation of the already
proposed solutions, but by using “instance_eval” I could avoid having
to create separate new/initialize-like methods for each constructor.

/Johan H.

#-------------------------------
class Point

def self.create_cartesian(x,y)
    allocate.instance_eval do
        @x = x
        @y = y
        self
    end
end

def self.create_polar(length,angle)
    allocate.instance_eval do
        @x = length * Math.cos(angle)
        @y = length * Math.sin(angle)
        self
    end
end

end
#-------------------------------


#16

On Wed, Mar 21, 2007 at 10:09:36AM +0900, Chad P. wrote:

I say “wonder” because I really am not certain in this case.
Well, it’s a choice. You can either have overloading or dynamic typing,
but
not both. The “pattern” is just a matter of having different names for
your
constructors. The simple, common case of a single constructor is
supported
by the new/initialize separation, but multiple constructors are still
pretty easy. Note that Objective-C, another Smalltalk-like,
dynamically-typed language, uses the same pattern.

CCD CopyWrite Chad P. [ http://ccd.apotheon.org ]
–Greg


#17

Chad P. wrote:

On Wed, Mar 21, 2007 at 08:32:37AM +0900, removed_email_address@domain.invalid wrote:

I have been using the following pattern to implement multiple
constructors for a class. It is only a variation of the already
proposed solutions, but by using “instance_eval” I could avoid having
to create separate new/initialize-like methods for each constructor.

I’ve heard it said – and I tend to agree – that regular use of
“patterns” is a sign that the language lacks something. I wonder if
that is the case with Ruby, as applies to multiple constructor behavior
implementation.

I say “wonder” because I really am not certain in this case.

Hi Chad! I don’t think Ruby “lacks” anything, it’s just that it has a
different way of doing things. It’s a trade-off between the flexibility
of a dynamic language and some other things like methods with same name
and different parameters (how are you going to distinguish between one
method that uses a string and an integer and another one that uses an
integer and a hash, if you don’t have types defined at the parameter
level?). If you want to do things “like Java” or “like C++”, then I
think you should open your mind and try to do things in a different way,
in a rubbish way.

Regards,

Nando


#18

Gregory S. wrote:

Well, it’s a choice. You can either have overloading or dynamic typing, but
not both.

Not true. Perl 6 will have optional static typing [1]. Sydney faked it
with a Behavior you could import (that used the parser to handle it, not
a compile time step, IIRC).

It’s possible. The question is whether or not it’s desirable. I vote
yes, others say no, and still others are in favor of some sort of type
inferencing. It’s been brought up before - you can search the archives.
:slight_smile:

Regards,

Dan

[1] http://www.perl.com/pub/a/2007/03/01/perl-6-parameter-passing.html


#19

On Wed, Mar 21, 2007 at 08:32:37AM +0900, removed_email_address@domain.invalid wrote:

I have been using the following pattern to implement multiple
constructors for a class. It is only a variation of the already
proposed solutions, but by using “instance_eval” I could avoid having
to create separate new/initialize-like methods for each constructor.

I’ve heard it said – and I tend to agree – that regular use of
“patterns” is a sign that the language lacks something. I wonder if
that is the case with Ruby, as applies to multiple constructor behavior
implementation.

I say “wonder” because I really am not certain in this case.


#20

Nando S. wrote:

Hi Chad! I don’t think Ruby “lacks” anything, it’s just that it has a
different way of doing things. It’s a trade-off between the flexibility
of a dynamic language and some other things like methods with same name
and different parameters (how are you going to distinguish between one
method that uses a string and an integer and another one that uses an
integer and a hash, if you don’t have types defined at the parameter
level?). If you want to do things “like Java” or “like C++”, then I
think you should open your mind and try to do things in a different way,
in a rubbish way.
^^^^^^^

I think you mean “ruby-ish”. :slight_smile:

Dan