Monday, August 7, 2006

Interfaces Should Be Modules

Currently, in order to implement a Java interface in JRuby, you extend from it like so:
require 'java'

include_class "java.awt.event.ActionListener"

class MyActionListener < ActionListener
def actionPerformed(event)
puts event
end
end

While documenting a JRUBY-66 workaround and thinking about a longterm fix, it hit me like a diamond bullet through my forehead: interfaces should be treated like modules.

My justification:

  1. You can include many modules, but only extend one class...just like interfaces. Currently in JRuby you can only implement one interface, which is stupid.
  2. Modules imply a particular set of behaviors not specific to a given class hierarchy...just like interfaces.
  3. Ruby implementations of Java interfaces can't extend any other classes; you can't both extend Array and implement Collection, if that were your goal.
  4. Ruby implementations of Java interfaces have bugs when defining initialize, since they don't really just implement that interface...they extend one of our JavaSupport proxies.
Item #1 will be of particular importance as we start using JRuby more and more to implement Java services. In my opinion, this is an unacceptable limitation on JRuby's Java integration capabilities.

Item #3 limits your ability to re-open core Ruby classes and add new Java interfaces to them, something that might greatly simplify mapping Ruby types to Java-land.

Item #4 is the cause of JRUBY-66, since we need to make sure the proxy's initializer is called.

In our defence, we inherited much of this Java integration behavior from the original project owners; however I think mapping interfaces to modules allows for much more powerful and uniform Java integration support.

I know it would be a fairly significant change to make Java interfaces
act like modules, but it seems much more logical to me. It's also primarily a new feature we could phase in, with the < syntax continuing to work for old style interface implementation.

Thoughts?
# yes, I know encapsulation would be better...this is just an example
...
include_class "javax.swing.JButton"

class MyActionRecorder < Array
include ActionListener

def actionPerformed(event)
self << event
end
end

Distributed Ruby (DRb) "Working Well"

A new member of the JRuby community, Blane Dabney, submitted a patch for JRuby socket IO to resolve a DRb issue he'd been having. Our original implementation of a "write" method was not properly handling line terminators, and would end up blocking on write calls with nothing coming out the other end. After some investigation by us both, Blane managed to put together a simple, working patch that solves the issue.

According to him, DRb from a Ruby client to a JRuby backend now "seems to be working well." I'm letting the patch stew for a bit, but it will likely be committed to trunk in the next couple days.

The ability to use DRb from Ruby to JRuby opens up a whole new world of integration with Java services. I guess it's time one of us got busy on a DRb-to-EJB gateway, don't you think?

Conference Updates

RubyConf*MI

I am registered for RubyConf*MI, though it's still uncertain if I'll attend. The registration cost is a measly $20, but it sounds like it will be a good time. Grand Rapids is about a 9-hour drive, however, so I'm looking for someone to share transportation with from Minneapolis. I probably won't go if it's just me alone.

MinneDemo

I'll be doing a quick (<15 mins) JRuby demo at Minnesota's first DemoCamp. I have no idea what I'll demo yet, but perhaps a more elaborate IRB-based Swing demo like that I did at JavaOne.

RailsConf Europe

Various events that are in mostion and which I won't elaborate on may lead to me attending and presenting at RailsConf Europe. Hopefully those events pan out (and hopefully there's enough time between now and the conf to get Rails working suitably well).

RubyConf

I may not be presenting, but I shall attend! I managed to secure one of the coveted registrations before they sold out two hours later. Regardless of corporate reimbursement, I'm going to make the trek to Denver. I hope to do an unofficial or "lightning" session on JRuby as well, since I know there are many attendees interested in hearing about it.

Sunday, August 6, 2006

Sunday Night Niblets

Camping

After a minor fix provided by Ola Bini (thanks Ola!) we now have Camping running under JRuby, using the ActiveRecord JDBC adapter. According to Ola, Camping under JRuby seems to run very well, and feels very snappy. I'm going to be playing with it a bit soon, and may have a demo site up by tomorrow.

JRuby Extras

The JRuby Extras project is officially launched on RubyForge. The ActiveRecord JDBC adapter is there and has received modifications to work with Oracle as well. The work thusfar on Mongrel is also there, and it appears that we may have Mongrel working under JRuby shortly. If you have a particular Ruby app that needs some JRuby-specific modifications or extensions, please let me know; this is a community-driven project to make Ruby apps spectacular under JRuby.

Thursday, August 3, 2006

Calling all Tor Norbyes

Ok, perhaps the blogosphere can help with this one. I've been trying to respond to an email from Tor Norbye at Sun Microsystems since Sunday. Unfortunately, my emails seem to be shuffled off into the ether. He sent another email to me today, saying he hasn't heard back from me.

Tor! I'm right here! Give me an alternate way to contact you...your Sun address seems to be kaput.

Wednesday, August 2, 2006

JRuby: It's pretty much my favorite animal.

Some of the local Rubyists and I were talking about publishers for a future JRuby book...ligers were brought up...and, well, here's the result.



It's just perfect...the lion of Java mated with the tiger of Ruby...and the magical JRuby is their offspring. It brings a tear to your eye, doesn't it?

Feel free to digg it.

Update: A couple folks have noted that O'Reilly's Java animal is already a tiger, so I guess I've got the roles reversed!

Busy Bees

I haven't posted anything substantive in a while, but things are moving rapidly forward. Here's a quick summary of what's been going on with JRuby:

RubySpec

I have launched an effort to build up a Ruby specification, Wiki-style. At The RubySpec Wiki, contributors can write short pages/articles on any aspect of Ruby: the language, the libraries, or the implementations. The eventual goal of this is to create a comprehensive library of content describing in detail how every aspect of Ruby is *supposed* to work. This in turn will help alternative implementations like JRuby, Ruby.NET, Cardinal, and others ensure they are functioning correctly.

CONTRIBUTORS ARE NEEDED! Please create an account and add whatever you can. Found out about a new feature, quirk, or bug in Ruby? Add it! Feel like porting over some core docs in a more spec-like format (i.e. including edge cases and formal semantics)? Go for it! The Spec will only succeed with user contributions. I may sponsor contests to see who can contribute the most...so keep an eye out!

The New RubyTests

The RubyTests project on RubyForge mainly houses the Rubicon suite, a collection of tests originally created for the first PickAxe book and based on Ruby 1.6. Over the past several years, it's been slowly, slowly updated for 1.8, but the library is showing its age. To complicate matters, other test libraries have sprung up to remedy some of Rubicon's deficiencies: BFTS, from the MetaRuby guys, and now a RubyTests project from the Ruby.NET team out of QUT. In addition, contributors to the RubySpec have called for a place to keep tests that go along with the specification. Something had to be done.

This past week, I sent out a proposal to all the RubyTests project members and the MetaRuby guys about finally unifying all our efforts under one grand test suite. The response so far has been excellent...Ryan Davis of MetaRuby told me he agrees with my plan, and others on the RubyTests project also agree this is the way to go. The wheels are in motion!

I will act as steward for the new RubyTests project, but only to fostor community collaboration. We'll initially consider pulling all the myriad projects under the RubyTests umbrella, and then start discussing issues like what testing framework to use, how or whether to generate tests, and how to provide traceability back to items in the nascent RubySpec. I encourage anyone interested in seeing Ruby improve and flourish on all platforms to join the project and contribute.

Block Refactoring Work

It recently became apparent that the current block-management code in JRuby (modeled almost exactly on C Ruby) is rather inefficient; doubly so in JRuby because we don't have C tricks like unions and longjmps. Tom also discovered after some research that much of the block-scoping semantics can be pulled out during the parsing process and stored, saving many searches later on. To these ends, we have both been working on refactoring JRuby internals to improve how blocks function.

I have been working to modify the call chain to pass blocks along as part of the frame. This simplifies a great many things, since the correct block to which to yield is now just a field-access away (and eventually, just an argument-access away). Previously, multiple stack pushes and pops were necessary to get the correct frame, causing great undue overhead. Also, I have rewired how Proc instances are invoked, so instead of two pushes and two pops on our internal "block stack", it now just calls the proc directly. Much cleaner. The eventual goal of this is to eliminate the "block stack" and also the "iter stack", which maintains a stack of flags indicating whether a block is available or currently executing.

Tom's work will make static much of the information about how blocks are scoped, since their relative orientation in the original source provides almost all the information we need. This will allow us to automatically or more quickly locate the appropriate variable when accessing such from within a block, as well as ensuring our variable scoping is handled correctly with multiple nested blocks. He is also keeping in mind that evals can change the list of variables, so the end result should work fine in those cases as well. The end result is that variable scoping will be much more reliable and performant when blocks are involved.

RubyInline for JRuby

After doing a bit of exploration on how Ruby extensions are written, I stumbled across yet another post from Ryan Davis about the beauty and simplicity of RubyInline. I am not a huge C fan, having had my fill of it during my old LiteStep days (I was lead LiteStep dev during the "great redesign" period), but the attraction of RubyInline is undeniable.

Ryan and I had a brief discussion over IM, during which we agreed that adding JRuby/Java support to RubyInline would be a really great idea. Then instead of just specifying C code in your RubyInline blocks, you could easily do the following:
class Example
inline(:C) do |builder|
builder.c "int test1() {
int x = 10;
return x;
}"
end
inline(:java) do |builder|
builder.java "public int test1() {
int x = 10;
return x;
}"
end
end

...and know that whether under JRuby or C Ruby, your inlined code would shine through. Look for this effort to pick up soon; Ryan has agreed to include it in RubyInline once it's ready.

Mongrel for JRuby

Danny Lagrouw and Ola Bini, perennial JRuby community superstars, have been working on implementing the native bits of Mongrel in Java. Danny put together a YACC-based HTTP request parser (since we don't have a Java Ragel yet) and today Ola implemented a quick ternary search tree in Java. With these two pieces working, we just have to wire up Mongrel and try it out in JRuby. It's very close.

What's the value of Mongrel when we have servlet containers to host Rails apps? That question answers itself. Name one Rails developer who's enamored of servlet containers. Yeah, I didn't think so. WEBrick is a poor substitute for a real container, and almost all Rails deployments are going Mongrel now. Not supporting Mongrel would be a showstopper for many, many Rails projects. Therefore, we're making it happen.

JRuby Extras!

I have requested a new project on RubyForge called "JRuby Extras". This project is intended to be a JRuby community love-fest, hosting all the bits and pieces needed to support Ruby apps running under JRuby. It will hold such juicy tidbits as:

  • The upcoming Mongrel support libraries (at least until they're hopefully included in Mongrel proper)
  • Nick Sieger's excellent ActiveRecord JDBC adapter (until included in Rails)
  • Any other JRuby-related extensions that don't have good homes elsewhere
  • Any Java or JRuby-related updates to other projects (like RubyInline) until included directly into those projects
Where the main JRuby project has only Tom and I as gatekeepers, the jruby-extras project will be more community-oriented. If you've got a good idea for how JRuby can be improved (think like Groovy, with its ten-thousand add-ons), toss us an email...and get busy!

The project, once approved, will be jruby-extras on RubyForge.

Standarizing JRuby Extensions

There are a number of extensions to JRuby internally, to replace missing C functionality from C Ruby. There are also a number of extensions being developed externally, to support things like Mongrel. Unfortunately, there is no standard way to write JRuby extensions like there is for C Ruby. The APIs that we expose are subject to change, and the Java world brings along its own conventions and expectations for how plugins ought to work. In order to settle this question, I have kicked off a thread on the JRuby dev mailing list.

We're going to figure out the best way to support JRuby extensions, along these rough lines:
  • Requiring an extension will look for an extension library just as it does in Ruby; however, it will be looking for a jar file in the load or class paths containing an appropriately-named entry point.
  • require "my/extension" will most likely look for extension.jar in under the my/ load or class path, and then load my.ExtensionLibrary contained therein
  • Since we'll want to use direct invocation now in JRuby, we'll want an easy way for extensions to have the same benefits. Rather than having them implement direct-callable interfaces, we'll likely build a code generator that can take a class and a list of method mappings and generate all stubs and callables needed for JRuby. This will also simplify our own code classes and extensions as well.
  • There are at least two ways within JRuby to define a new class, its metaclass, and their methods. One is easy but a bit broken; the other is correct but cumbersome. Extension writers will get something in the middle...easy but correct, via various helpers and factories. The same model will also be applied internally. Unification!
Making a Move

On a more personal note, there are events afoot that may give me more time to work on JRuby. I won't go into specifics...just let your imagination run wild.