Difference between 1.9.2 and 1.9.3

module A <- line 1
def initialize(*args, &block)
super
end
end

class B
include A
def initialize(name)
super
end
end

B.new(‘foo’)

…executed without warnings under ruby 1.9.2 but under 1.9.3-p125 it
gives me:

test.rb:3:in initialize': wrong number of arguments(1 for 0) (ArgumentError) from test.rb:3:ininitialize’
from test.rb:10:in initialize' from test.rb:14:innew’
from test.rb:14:in `’

Not calling ‘super’ in initialize in module A fixes it but then it seems
that module A is not as generic and standalone in terms of how its
included by classes. I guess its more correct because there is no super
class in this case. What should I change the code to for the best?

Cheers,
James

On Mon, Feb 20, 2012 at 12:25, James F.
[email protected] wrote:

module A ← line 1
def initialize(*args, &block)
super
end
end

test.rb:3:in `initialize’: wrong number of arguments(1 for 0)
(ArgumentError)

Not calling ‘super’ in initialize in module A fixes it but then it seems
that module A is not as generic and standalone in terms of how its included
by classes. I guess its more correct because there is no super class in this
case. What should I change the code to for the best?

Try using parens on super, i.e., super(). That should stop it from
passing along the args the initializer got.

-Dave

That’s because super with parentheses passes the same args your method
was called with (like Dave said), and default Object#initialize method
takes no arguments.

But that’s interesting. You might want to metnion it at Ruby’s bug
tracker: bugs.ruby-lang.org - maybe the default initializer should
take any number of args and just discard them.

– Matma R.

2012/2/21 Dave A. [email protected]:

On Tue, Feb 21, 2012 at 9:40 AM, Bartosz Dziewoński
[email protected]wrote:

That’s because super with parentheses passes the same args your method

I assume this was a typo, meaning “without” parentheses.

was called with (like Dave said), and default Object#initialize method
takes no arguments.

But that’s interesting. You might want to mention it at Ruby’s bug
tracker: bugs.ruby-lang.org - maybe the default initializer should
take any number of args and just discard them.

I think that is not a good idea. With the current implementation, it
is still possible to add optional arguments later. If a method (e.g.
initialize) would accept any number of arguments and just discard
them, then later on, adding 1 or more optional arguments in the
definition would suddenly cause bugs as these initially discarded
arguments would then interpreted as a real, optional argument.

Just write super() when calling the higher up initializer.

HTH,

Peter

On Feb 21, 2012, at 11:00 AM, Peter V. wrote:

take any number of args and just discard them.
HTH,

Peter

I didn’t know this actually made it into 1.9.2, but for a while, the
default
initialize method took a variable number of args and just dropped them.
It
was reverted a while back.

Best regards,
Florian

From: [email protected]
[mailto:[email protected]] On Behalf Of Peter V.
Sent: 21 February 2012 10:01
To: ruby-talk ML
Subject: Re: Difference between 1.9.2 and 1.9.3

On Tue, Feb 21, 2012 at 9:40 AM, Bartosz Dziewoński
<[email protected]mailto:[email protected]> wrote:
That’s because super with parentheses passes the same args your method

I assume this was a typo, meaning “without” parentheses.

was called with (like Dave said), and default Object#initialize method
takes no arguments.

But that’s interesting. You might want to mention it at Ruby’s bug
tracker: bugs.ruby-lang.orghttp://bugs.ruby-lang.org - maybe the
default initializer should
take any number of args and just discard them.

I think that is not a good idea. With the current implementation, it
is still possible to add optional arguments later. If a method (e.g.
initialize) would accept any number of arguments and just discard
them, then later on, adding 1 or more optional arguments in the
definition would suddenly cause bugs as these initially discarded
arguments would then interpreted as a real, optional argument.

Just write super() when calling the higher up initializer.

HTH,

Peter

Calling super() does fix this trivial example but I also happen to
include the module from a class that inherits from another class before
Object, so it breaks that. What we need to figure out is how does one
write initialize() in a module such that it seamlessly integrates into
any inheritance chain in 1.9.3. It doesn’t seem possible (at least
without some hacking) in 1.9.3. Maybe it is actually a bug somewhere.

I will probably hack round it with

def initialize(*args, &block)
if self.class.superclass === Object
super()
else
super
end
end

Is there a better way?

On Tue, Feb 21, 2012 at 4:17 PM, James F.
[email protected] wrote:

Thanks for the help and input (as always Robert!), but I’ve got the feeling
you’ve just restated my initial problem.

I don’t think so. I just said that your 1.9.2 is buggy if it does not
throw.

Here is some more code. If you could tell me precisely what to change to make it
work without hacking around (which is what I want!) then I’d be very grateful :slight_smile:
Notice that module A is included both by a class that doesn’t inherit and by one
that does.

Exactly as I said:

~$ diff -U5 x.rb xx.rb
— x.rb 2012-02-21 16:38:04.791899100 +0100
+++ xx.rb 2012-02-21 16:40:38.587789800 +0100
@@ -18,11 +18,11 @@
end

class D
include A
def initialize(name)

  • super
  • super()
    end
    end

B.new(‘foo’)
D.new(‘bar’)

Cheers

robert

2012/2/21 Robert K. [email protected]:

def initialize(name)

  • super
  • super()
    end
    end

B.new(‘foo’)
D.new(‘bar’)

I think the point is that this will not pass the arguments to module’s
#initialize.

– Matma R.

-----Original Message-----
From: Robert K. [mailto:[email protected]]
Sent: 21 February 2012 15:42
To: ruby-talk ML
Subject: Re: Difference between 1.9.2 and 1.9.3

On Tue, Feb 21, 2012 at 4:17 PM, James F.
[email protected] wrote:

Thanks for the help and input (as always Robert!), but I’ve got the feeling
you’ve just restated my initial problem.

I don’t think so. I just said that your 1.9.2 is buggy if it does not
throw.

Here is some more code. If you could tell me precisely what to change to make it
work without hacking around (which is what I want!) then I’d be very grateful :slight_smile:
Notice that module A is included both by a class that doesn’t inherit and by one
that does.

Exactly as I said:

~$ diff -U5 x.rb xx.rb
— x.rb 2012-02-21 16:38:04.791899100 +0100
+++ xx.rb 2012-02-21 16:40:38.587789800 +0100
@@ -18,11 +18,11 @@
end

class D
include A
def initialize(name)

  • super
  • super()
    end
    end

B.new(‘foo’)
D.new(‘bar’)

Cheers

robert

Thanks Robert, I had not spotted that. I am very grateful :slight_smile:

On Tue, Feb 21, 2012 at 11:44 AM, James F.
[email protected] wrote:

wrote:
Just write super() when calling the higher up initializer.

But do it in the child class not in the module!

def initialize(*args, &block)
if self.class.superclass === Object
super()
else
super
end
end

Is there a better way?

IMHO the quoted 1.9.2 version is the buggy one because it should have
raised an error in the first place. The most portable way to write a
module #initialize method is to do

def initialize(*a, &b)
super

module init

end

or, if you like to be explicit

def initialize(*a, &b)
super(*a, &b)

module init

end

Because then you can insert it into any inheritance hierarchy. And
your “hacking around” is not necessary. In cases where the superclass
is Object the real culprit is the child class: that should use
“super()” and not “super” because it knows its super class and knows
the argument list.

I think it is a bad advice to do

def initialize(*a, &b)
super() # always no args!

module init

end

This will only work in cases where the super class or the module
next in inheritance hierarchy does not accept arguments.

Kind regards

robert

2012/2/21 Bartosz Dziewoński [email protected]:

include A
#initialize.
But arguments are not uses in the example and there was no statement
which would indicate that fact. James, what is it that you really
need?

It’s generally problematic to have module initialization with
arguments: if you have a module which needs arguments for
initialization you limit the usability because all classes using it
must be aware of this fact (i.e. pass proper arguments). Plus, all
these classes must have a superclass or (supermodule, i.e. next module
in inheritance chain!) constructor with the exact same number and
order of arguments because the module constructor must decide how to
pass stuff on. I think that interferes with the concept of “mix in”
module which you can use in many places and even add to classes later
on.

You can remedy that a bit by doing something like this in a module’s
initialize

Will read first argument as name if present

def initialize(*a, &b)
@name = a.first # nil if missing
end

If there is so much common state to initialize then this might be an
indication of more tight coupling between class D and B or C and that
it might be better to change the inheritance hierarchy (i.e. make D
inherit B as well). Generally inheritance initialization is tricky in
a language with so much dynamic where the inheritance hierarchy can
change any time…

Kind regards

robert