On Thu, Jun 28, 2012 at 5:30 PM, Cees Z. [email protected]
wrote:
In JRuby, I am extending an existing Java Class with a Ruby initialising
block by redefining the ‘new’ class method.
That does not sound like a good idea. Class#new should only be
overridden if you need to adjust the initialization process. What are
you trying to achieve with that?
This works fine except for new classes which inherit from the original
class and have a different number of arguments.
These classes generate a ‘wrong number of arguments’ error.
The behavior seems not specific for Java Classes and is actually the
same for Ruby and JRuby.
The following example illustrates it, the first version works as
expected
My example
irb(main):001:0> class A;end
=> nil
irb(main):002:0> A.method :new
=> #<Method: Class#new>
irb(main):003:0> class B<A;end
=> nil
irb(main):004:0> B.method :new
=> #<Method: Class#new>
irb(main):005:0> def A.new(x) printf “This won’t work, but anyway %p\n”,
x end
=> nil
irb(main):006:0> A.method :new
=> #<Method: A.new>
irb(main):007:0> B.method :new
=> #<Method: B(A).new>
irb(main):008:0> A.new 1
This won’t work, but anyway 1
=> nil
irb(main):009:0> B.new 2
This won’t work, but anyway 2
=> nil
irb(main):010:0> irb(main):001:0> class A;end
=> #<Method: Class#new>
irb(main):003:0> class B<A;end
=> nil
irb(main):004:0> B.method :new
=> #<Method: Class#new>
irb(main):005:0> def A.new(x) printf “This won’t work, but anyway %p\n”,
x end
=> nil
irb(main):006:0> A.method :new
=> #<Method: A.new>
irb(main):007:0> B.method :new
=> #<Method: B(A).new>
irb(main):008:0> A.new 1
This won’t work, but anyway 1
=> nil
irb(main):009:0> B.new 2
This won’t work, but anyway 2
=> nil
The next example adds a redefinition of Parent.new; Parent goes on to
work as expected, but Child fails:
Method Class#new must always have signature (*a, &b) because otherwise
it cannot properly forward arguments to #initialize. As you can see
this is the case for Class#new already:
irb(main):021:0> Class.method(:new).arity
=> -1
It has to be that way because #initialize of sub classes actually
defines the signature of the constructor. Method Class#new basically
does something like this:
irb(main):001:0> class A
irb(main):002:1> def initialize(x) @x=x end
irb(main):003:1> def self.new(*a,&b)
irb(main):004:2> puts “before”
irb(main):005:2> x = allocate
irb(main):006:2> printf “allocated %p\n”, x
irb(main):007:2> x.send(:initialize, *a, &b)
irb(main):008:2> printf “initialized %p\n”, x
irb(main):009:2> x
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> e = A.new 123
before
allocated #<A:0x80319e78>
initialized #<A:0x80319e78 @x=123>
=> #<A:0x80319e78 @x=123>
There is only reason if you want to change allocation of instances of
a class (e.g. by taking them from a pool of preallocated instances or
such). This is rarely the case.
Is this behavior intentional or a bug? At least it is consistent (Ruby
1.8.7, 1.9.1 JRuby 1.6.7)
I think it is intentional and consistent because if you introduce
specific storage characteristics for a class you’ll likely want all
subclasses to share it. The same happens with singleton methods of
class instances generally:
irb(main):001:0> class A;end
=> nil
irb(main):002:0> class B<A;end
=> nil
irb(main):003:0> A.methods.grep /foo/
=> []
irb(main):004:0> B.methods.grep /foo/
=> []
irb(main):005:0> def A.foo() puts 123 end
=> nil
irb(main):006:0> A.foo
123
=> nil
irb(main):007:0> A.methods.grep /foo/
=> [:foo]
irb(main):008:0> B.methods.grep /foo/
=> [:foo]
irb(main):009:0> B.foo
123
=> nil
That way properties you define on a class are available for subclasses
as well.
irb(main):010:0> class <<A; attr_accessor :bar end
=> nil
irb(main):011:0> A.bar=9
=> 9
irb(main):012:0> B.bar
=> nil
irb(main):013:0> B.bar=123
=> 123
irb(main):014:0> B.bar
=> 123
I have tried using alias instead of super and changing the order of
redefining new and defining initialize. I also tried using class_eval
and taking the Person.new definition out of the original class
definition. All to no avail.
Any help would be appreciated.
Please first explain what your goal is.
Kind regards
robert