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?
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.
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.
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.
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.
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
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
Notice that module A is included both by a class that doesn’t inherit and by one
that does.
-----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
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
Notice that module A is included both by a class that doesn’t inherit and by one
that does.
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.
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
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.