Taking notes on this thread on how some decisions might need to be made.

Interface logic is all pretty easy and working already. If you are
extending an existing Ruby class or no class (Object) and include
interfaces, the logic goes like this:

1. A new class is generated, with the superclass being whatever the
Java-side class is for the Ruby-side superclass. For example, "class
Foo; include Runnable; end" would have as its Java superclass
org.jruby.RubyObject. "class Foo < String; include Runnable; end"
would have as its Java superclass org.jruby.RubyString. This allows
extending existing Ruby core types and adding an interface
impl...something that was not possible before.
2. All interfaces included so far are tallied up and their methods
aggregated by name. All methods get implemented (to appease Java type
requirements for interface impls) so that they dispatch directly to
the single named Ruby method. For example, if you have five overloads
for "valueOf" they'll all dispatch to a single Ruby method named
"valueOf" or "value_of" (or else to method_missing).
3. The resulting "real" class is set up as the backing store for the
Ruby class, so that all instantiations now actually construct
instances of that generated Java class. This allows both the Ruby
world and the Java world to see exactly the same object.

Class extension is more complicated...

When a Ruby class extends a Java class, we ideally want it to still be
an IRubyObject so it can pass through JRuby calls without a wrapper.
But this requires implementing all the IRubyObject methods.

I have partially solved this on my branch by having a new
BasicObjectStub with simple versions of all the IRubyObject methods,
and a BasicObjectStubGenerator that can create all the method bodies.
The new class extension logic uses this to "fill in the blanks" so
that the "real" class can actually extend the one you specified, but
also implement IRubyObject and pass through JRuby successfully. This
does increase the size of the class a good amount since the
IRubyObject interface is pretty large, but those are the breaks. Until
a miracle happens and we can eliminate IRubyObject in the call path,
this is the most straightforward way.

The trickier bits of extension are still unimplemented, however:

** Constructor sequences **

We would like our "initialize" to actually serve the role of the
Java-land constructor, but that's tricky; the typical sequence for
construction is to first allocate the object and then call initialize
against it with initialization arguments. In Java, you never see the
allocate phase, and the entire construction process passes through the
constructor method. We need a way to unify the two construction paths
in a reasonable way.

We also need our constructor to store off the original Ruby instance
and RubyClass the object should be associated with, while still
allowing no-arg construction for reflective construction from Java.
This may force the issue of moving Ruby to being classloader-global,
so that any classes generated under a given JRuby instance will know
automatically which Ruby instance they came from.

** Super and "special" calls **

Subclasses need to be able to call protected members of the superclass
as well as invoke the superclass's constructor.

For protected methods, we currently just set them "accessible" so they
can be invoked from anywhere. It's not an ideal solution, however,
since it doesn't work in secured environments and can be costly. We
*could* generate bridge methods in the subclass for all protected
methods from the superclass, but that could be too many when you
consider deep hierarchies with lots of protected methods. We'll need
to look into what Groovy does and see if we can do that, though I
suspect they solve it by using setAccessible.

The "special" calls I mean are superclass constructor calls, which are
only callable from within the child class and potentially only from
within the child class's constructor. I'm not sure there's any way to
get around this, and I know that Groovy has had to deal with the same
challenge since the actual logic for their dispatch may not happen in
the actual constructor body. We'll need to do some experimentation
here.

** Abstract methods **

Like for interfaces, we will need to automatically implement all
abstract methods from the parent class to do dynamic calls. If we
don't, it won't be possible to extend abstract superclasses using
metaprogramming or method_missing. We may even want to consider doing
this for *all* overridable methods from the superclass, so that any
one of them can be dynamically replaced such that both the Java and
Ruby worlds see it. We'd be the first and only JVM dynamic language to
take things to this level; even Groovy ends up being mostly stuck with
the original method definitions when called from Java.

** Better IRubyObject stubs **

The current stubs are pretty weak. They don't allow Ruby instance
variables at all on concrete subclasses. They don't do anything with
freezing. They punt on a number of things, and we'll probably want to
improve them. In addition, there's going to be cases in current JRuby
code where we assume IRubyObject instances always extend
RubyBasicObject or RubyObject and cast unconditionally. We'll need to
search those out and replace them with something more agnostic.

...

That's about all I have at the moment.

On Wed, Dec 16, 2009 at 12:28 AM, Charles Oliver Nutter
<[email protected]> wrote:
> I'm working on a new branch of code ("newji" on the kenai repository)
> that has started to add the following features:
>
> * Ruby classes implementing a Java interface will actually be instance
> of a *real* Java class created on first instantiation. No more
> two-headed object and chicken/egg initialization hassles.
> * Ruby classes extending Java classes will *actually* extend those
> classes and be *real* instances of the resulting class. No more
> two-headed...
>
> This is part of a first effort to unify all the various
> class-generation schemes we have, from the standard JI (generating
> little stub classes and wrapping them) to ruby2java (generate real
> classes ahead-of-time that dynamically invoke via Ruby classes) to
> become_java! (generate real classes at runtime). The ultimate goal of
> this is to finally make Ruby's type hierarchy fit correctly into
> Java's type hierarchy, to bridge the remaining integration gap with
> languages like Scala and Groovy.
>
> This first step is already working very well for interface
> implementation. Check out this gist:
>
> http://gist.github.com/257634
>
> This shows a Foo class that implements Runnable. When instantiated,
> the instance of Foo is actually *physically* an instance of the
> generated Java class. There's no wrapping layers at all, and the
> object can be reflectively manipulated.
>
> The extension logic is shown there as well, but its not as
> full-featured as the existing (extremely complex) logic. However
> filling in the blanks will not be particularly difficult, and that's
> what I'll be working on the remainder of this week. Next steps will be
> to work out how to get "initialize" and Java construction to cooperate
> nicely and adding back the features that the current class-extension
> logic does (like implementing abstract methods for you).
>
> Once the basic logic for those two halves of Java integration code
> generation are working as well as before, all the become_java! logic
> will be added. This will essentially merge become_java into normal
> Java integration, allowing you to add annotations, specify signatures,
> and so on.
>
> The final, and most complex step, will be to get this all to work
> ahead of time as well. This will require much more work and probably
> will not go into this upcoming release. Basically we need a way to
> determine statically) or through a minimal load process, like
> ruby2java does) what classes to generate, what classes they extend and
> interfaces the implement, and all their methods and annotations. It's
> not so much a code-generation problem as a Ruby DSL/parsing/compiler
> problem. But it's solvable, like all things.
>
> I'm starting to get very excited about this work. A change this major
> would start to warrant a JRuby 2.0, with one other 2.0 piece being the
> new interpreter/compiler. I'm starting to think 2010 is the year
> JRuby's finally going to meet all the loftiest goals we've set for
> it...
>
> - Charlie
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply via email to