IronRuby Q&A – What’s Down With Microsoft’s Ruby Implementation In 2010?

IronRuby is an open source Ruby implementation being developed at Microsoft with the .NET CLR in mind. It’s reasonably mature and as well being a regular implementation, it provides the ability to use Ruby directly within the Web browser through Microsoft’s Silverlight Flash-esque framework. Windows seems to get a bad rap in the Ruby community so we thought we’d turn the spotlight on some of the cool things IronRuby’s doing nowadays.

Being based on the .NET CLR presents some unique challenges for IronRuby. So far IronRuby passes 86% of the RubySpec (compared to a 98% pass rate for the MRI on Windows) but this number is creeping up every week. To learn more, I caught up with developer Jimmy Schementi of Microsoft to ask some questions about the project and its workings.

grantmichaels: There are ~150 native extension gems for Ruby, some of which are prolific and often depended upon by other gems. Does your Ruby implementation support FFI (foreign function interface) at present, and/or how much of a priority is running native extension gems going forward?

Jimmy Schementi: IronRuby does not support the Ruby C API which extensions depend on today, and there are no plans to support it either; it’s too difficult to support 100%. However, we do have plans post 1.0 to support FFI, as native code interop from Ruby is very important to IronRuby; it’ll make the implementation able to talk directly to native code when running on .NET or Mono. Keep in mind the Win32API is supported in IronRuby, so you can call Win32 functions without writing C#. Today IronRuby developers have to write some C# code which can interface with non-Win32 native code, through the platform invoke APIs, which turns out to be not any more work than using FFI would be, but it does require breaking outside of IronRuby. From there IronRuby lets you consume the C# code without an interop layer.

Passing RubySpec tests is fundamentally important for a modern, robust Ruby implementation. Has this compliance lowered the theoretical performance ceiling of your implementation considerably?

Of course, but can you think of another way? I think every language implementation will tell you that during the very early stages of development they were blazing fast, but as they got closer to implementing compliant Ruby functionality, performance suffered, or it just got harder and harder to keep the implementation at the same level of performance. But that’s understandable for a language like Ruby; it puts the burden of cleverness on the language, rather than developer writing applications in Ruby.

Keep in mind though, RubySpec is not for performance testing. And while the ruby-benchmark suite is a fine benchmark suite, the most beneficial performance improvements for IronRuby have come from analyzing and optimizing actual programs, like Rails, RSpec, RubyGems, Cucumber, IRB, etc. RubySpec did play a role here, as it helped make sure we didn’t degrade in compliance while using the real applications for performance tuning. Also, we have analyzed MSpec (RubySpec’s test runner) on IronRuby for startup and throughput performance.

Closures, continuations, and tail-call optimizations are often discussed in terms of programming language VM’s. Which of these attributes are implementable at present, which are expected to be implemented, and which are not possible by design?

Closures aren’t really a VM feature, as they are just a block of code executing in a context. As the Dynamic Language Runtime is a language-implementing tool, it does support closures, but IronRuby does not use them; they are forked in IronRuby, though we’d like to put our updates in the next version of the DLR.

However, the Common Language Infrastructure does provide a big part of what a closure is; the block of code, which is called a Delegate. Delegates are essentially function pointers, though they are first-class objects in the CLR, so the can be part of a method signature, stored on other objects, garbage collected, and have any other properties that objects have. Coupled with DynamicMethods, which allow for at-runtime IL (the CLR’s intermediate language) generation and conversion to delegates, IronRuby is able to directly invoke CLR code, as well as expose Ruby methods as delegates for CLR code to use.

Although continuations are not part of the ISO CLI, though Mono now supports microthreading and coroutines on top of the CLI. which allows them to implement continuations. Microsoft’s CLR does not support continuations, so IronRuby does not have support for the “callcc” today. IronRuby could support true continuations only when running on Mono, but only if IronRuby users pushed for it, and even then we’d really like to avoid different behavior based on the runtime.

IronRuby does not have any support for tail-call optimization. Tail-call optimization is supported by the CLR, but it’s not automatic; IronRuby must detect this and correctly emit the opcode for tail-call optimizations, and even then the code needs to fit a specific criteria for the just-in-time compiler to recognize the opcode. However, the CLR’s way of supporting it is not why IronRuby doesn’t support it; in real Ruby code you’d probably never see tail-call optimization happening, so we haven’t seen a need for optimizing this. Tail-call optimization’s main benefit in functional languages is to reuse the caller’s frame by replacing recursion with a loop, rather than creating a new frame for each recursive call. In Ruby this optimization would be irrelevant if a block or proc was used in the caller, since a new frame would be required for each.

How integral is dynamic feedback-based optimization to reaching a high level of performance? Do you feel it will be possible to maintain acceptable speed into the future without embracing these strategies or are there less well-known alternatives which are potentially more effective?

If by “dynamic feedback-based optimization” you mean “inline caching”, then it is very integral to performance of IronRuby. The Dynamic Language Runtime, which IronRuby uses for a target syntax tree, code generation, and interop with the CLR, uses “polymorphic inline caching”, which means it caches all call signature a method encounters, turning subsequent calls to the same method (with the same signature) into a cache lookup for a delegate representing the method.

What are your thoughts on the Ruby programming language in the context of distributed programming?

As the number of processors are becoming more and more crucial to the overall speed of CPUs, Ruby needs to make distributed programming a first-class concept in the language to ensure it’s continued usage in this changing computing landscape.

The Ruby language is very expressive, and I have no doubt the distributed programming paradigm will fit seamlessly into Ruby’s syntax. Ruby’s first-class closures and syntactic-sugar around them (blocks) are a natural way of expressing parallel operations. Also Ruby’s enumerators and future features like a lazy-array provide the right tools to make parallel programming even easier.

However, Ruby does not have native thread support, so anything that will run truly in parallel will need to run cross-process. While this will work great for MRI, other implementations will have to find ways to make this work well on their platform. I see this as place where the various implementations of Ruby can step up and provide a native runtime-based way of running programs in parallel. For IronRuby, we could utilize the Parallel Extensions libraries to build any Ruby-based parallel support on-top of. In fact, these libraries could be used directly from IronRuby today. For more information about writing parallel software on the CLR, there is a detailed paper as well as a good amount of examples.

Which of 1.8.7 and 1.9.x is your implementation compatible with?

IronRuby 1.0 targets compatibility with the latest patch-level of 1.8.6. IronRuby does have a “-19” flag to enable any Ruby 1.9 features implemented along the way, but it will be disabled for the 1.0 release.

IronRuby 1.x will drop 1.8.6 support and only target the latest version of 1.9. There won’t be a specific version which targets Ruby 1.8.7, but those features will probably be the first set of things implemented in the 1.x branch. IronRuby 1.0.x will be a servicing branch for IronRuby 1.0, and that branch will continue to only support 1.8.6.

Do you think further acceptance of Ruby is driven equally by spending man-hours working on performance and by meeting an international body’s specification?

As a Ruby implementer, I welcome a specification for Ruby that everyone agrees on as what makes Ruby the excellent language it is, as long as it doesn’t hinder adding future features to the language. Having a specification will probably make it easier for implementations to achieve acceptable performance, because they can design their system with all the requirements of Ruby in sight.

What are your team’s goals for the next quarter, the next year?

IronRuby 1.0 will be released withing the next quarter, with the goals of improving startup significantly, getting RubySpec passing at over 95% across the board, and ensuring compatibility with popular application test suites and scenarios. We will also invest some time in taking advantage of the new features in .NET 4 and Silverlight 4, as well as a push to ensure compatibility with the latest version of Mono.

For the next year, the IronRuby team will focus on 1.9 compatibility, explore tooling options in Visual Studio 2010, and support Ruby and Windows developers to make IronRuby a premier Ruby implementation for Windows.

Besides any obvious platform niche, why might someone benefit from electing to use your Ruby Implementation?

When you ignore the platform niche all implementations of Ruby are pretty similar. In fact, it’s the underlying platform that gives one flavor of Ruby advantages over another. For example, MRI has extremely fast startup compared to other flavors, but lacks the rich graphical libraries that Java and .NET have. In the end it’s all about what’s most important to the Ruby user, and in IronRuby’s case there are lots of platform-related benefits, some of which include .NET’s integration into the native Windows GUI system, running Rails on Windows through IIS — along-side other ASP.NET website, running in the browser through Silverlight, and the Parallel Extensions library I mentioned earlier.

How much of an advantage is it that you aren’t also responsible for maintaining the VM?

Well, for starters it’s one less place we have to be responsible for bugs, though working-around any bugs is our responsibility. We don’t have to worry about VM issues across different platforms, as the CLR and Mono take care of that for us. Mono is extremely fast in fixing any bugs we discover, like a matter of days, which definitely beats fixing them ourselves. From a ecosystem point-of-view, other things that built on-top of the CLR get interop with Ruby code for free, like running in the browser through Silverlight/Moonlight, and CLR-based debuggers (like MDbg, Visual Studio, and MonoDevelop).

Windows Vista and aboves with .NET pre-installed, most Linux distributions pre-install Mono or it’s readily available via packages, and Mono is also easily installable on Macs. Despite that, a number of Rubyists somewhat disregard IronRuby for having any relationship whatsoever to .NET. Are they throwing the baby out with the bathwater?

I’d say so, but they don’t necessarily need to “switch” to IronRuby; all Ruby implementations have their own uses. Ruby is unique in that it runs almost anywhere, giving Rubyists a plethora of tools to choose from to solve their problems, while still writing code in Ruby. In fact, this ubiquity makes Rubyists more valuable developers. As Ruby becomes a more accepted language for .NET shops to use, Ruby developers will be in high demand.

[job] Northwestern University (Chicago, IL) is looking for a Rails developer at the Feinberg School of Medicine on their downtown Chicago campus. Experience with BDD, Agile, and CI essential.

In-depth JRuby Q&A: What Makes JRuby Tick in 2010?

jruby1JRuby is undoubtedly the most mature of the alternative Ruby implementations. Supporting Ruby 1.8.7 and 1.9.1 (mostly!) and JIT compilation, JRuby is already in use in mission critical Ruby apps and runs scarily fast on the JVM. In this interview with JRuby core member, Charles Nutter, we dig deep into what makes JRuby tick.

A great deal of conversation on IRC, as well as quite a number of lengthly emails, were eventually corralled into the following Q/A session between Charles Nutter and myself.

JRuby and Rails are the ideal solution for building new enterprise web applications. With JRuby’s ability to seamlessly integrate with anything Java, and Rails’ strong REST principles, these new applications will be 100% WOA compliant themselves, and also may trivially extend WOA compliance to the underlying Java systems. Rails makes it easy and inexpensive, and JRuby leverages the capacity, manageability and security of existing Java deployment farms.

— Tom Mornini (@tmornini)

The JRuby guys are doing the hard, bone-crunching work of exposing a high-quality Ruby implementation to millions of new developers. It’s not glamorous work, but the work they’ve been doing has already changed the landscape of Ruby, and there’s much more work still to come.

— Yehuda Katz (@wycats)

The JRuby / Charles Nutter Q&A

It’s frequently mentioned that the HotSpot JVM has 500+ man-years invested, and you’ve mentioned not only how infrequently you experience faults within the JVM, but at once how quickly they are addressed by the Hotspot team. How much of an advantage is it that you aren’t also responsible for maintaining the VM?

It is a tremendous advantage for anyone using an existing VM. Many folks don’t realize how much effort is required to build a new VM from scratch. You need a reliable optimizing compiler that not only makes code run fast, but does not change the execution results of users’ programs. You need memory management and garbage collection systems that limit pauses, keep memory usage within reasonable levels, and don’t become performance problems for systems under load. You need safe and reliable native interfaces that protect the integrity of VM internals. If you can achieve those items, you may want real concurrent threading that doesn’t cause the runtime to crash in unrecoverable ways. You may want tunable settings, like those added to REE to adjust garbage collection parameters. You will almost certainly want debugging and profiling interfaces that don’t drastically impact performance. You may want management interfaces that allow you to monitor and configure the system at runtime. You may want security guarantees, so users can safely sandbox code and be certain it will remain within operating parameters. And ideally, you want experts working on all these subsystems. That’s exactly what you get with the JVM.

And it goes even farther than that. There’s not just one JVM, there’s at least three in widespread use: Sun’s Hotspot, the VM behind OpenJDK; Oracle’s JRockit; and IBM’s J9. Each one has whole *teams* of developers working on those subsystems. And each company has competed for years to make their JVM better than the others. There are JVMs for every platform in use; we’ve gotten bug reports from users on exotic systems like Z/OS and OpenVMS. There are VMs that run on the smallest embedded devices and on the largest many-core systems you can imagine (see Azul’s JVM and hardware, running on hundreds of cores with hundreds of GB of memory). There have been JVMs on mobile phones for almost a decade. Every Blu-Ray player runs a JVM. There are JVMs literally everywhere.

It’s impossible to measure how much effort we’ve saved by building atop the JVM … but it’s a tremendous amount.

Garbage collection in MRI Ruby has been singled out as a significant performance issue. HotSpot has been said to have a sophisticated and excellent garbage collection strategy. How important is garbage collection for all Ruby implementations? How important is it for JRuby specifically?

Ruby is an extremely GC-intensive language. Much of the performance improvement in the upcoming Rails 3 comes from reducing object churn and therefore reducing the amount of GC necessary. Another example of this is the success of REE, in large part due to performance-improving patches to the MRI garbage collector. There are many such examples, and as a result, you simply can’t have a high-performance Ruby without a high-performance GC.

In JRuby’s case, we can leverage the years of effort that have gone into the JVM GCs. On Hotspot, the JVM we generally test against, you have not one but as many as 5 different garbage collectors to choose from. There are collectors that optimize straight-line allocation and GC performance (like Hotspot’s “throughput collector”). There are collectors that spread collection across cores to reduce pauses (the “parallel collector”). There are collectors that run nearly pauseless, running some collection phases concurrently with your application’s code (the “concurrent collector”). There are collectors that focus on aggressively localizing objects of similar ages so they can be collected in groups (the G1 “garbage first” collector). These collectors can often be mixed and matched depending on how your application behaves (or how you need it to behave). And they all can be almost infinitely tuned and monitored.

JRuby’s performance on numeric benchmarks serves as another example of how well JVMs manage memory…

One feature the JVM does not yet have is “fixnums”. Fixnums, in the VM world, are the ability to treat certain numeric values as though they were objects, without them actually being objects. Usually, this is achieved by dedicating a range of memory addresses as “tagged integers”, so that by masking off a few bits, you get the actual numeric value. This could, for example, reduce the cost of “boxing” integer values in java.lang.Integer objects to almost zero, allowing them to behave like objects but take up no memory on the heap and require no special attention from the garbage collector.

All the MRI-based implementations use “true fixnums”, as do several of the alternative implementations. JRuby does not, since the JVM does not support fixnums yet. As a result, we have to actually allocate a fixnum object for almost every math operation or for each iteration of a numeric loop. Those objects take up heap memory and eventually have to be collected.

We’ve always accepted that we’d eventually be surpassed on numeric performance, since fixnums have a much higher cost for us. But even though some of the newer fixnum-supporting implementations have better numeric performance than JRuby, we’re still able to come very close–even with all that fixnum object churn. Our numeric performance rarely impacts typical applications, and that’s a testament to the performance of the JVM’s memory subsystem.

(FWIW, there are several other JVM languages crying for “true fixnums”, and I’d be very surprised if we didn’t see an implementation within the next year.)

It’s a very different sensation to develop with JRuby with regards to start-up time. How are people minimizing this impact in production today, and what might be done to improves this micro-benchmark in the future?

Start-up time is one of those areas JVM engineers have unfortunately neglected until recently. JVM engineering has, for most of its lifetime, focused on the performance of long-running applications. Indeed, the best performance of JRuby (and other JVM languages) comes after not just slow startup but after a substantial warm-up period. This works great for server-side applications, but client-side use–whether for test-driven development, command-line tooling, or quick scripting–can sometimes be painful to deal with.

There’s also a culture clash here. Basically all JVM-based developers do their development inside an IDE, which often can run tests in the same JVM process from run to run. And JVM engineers have only recently started focusing efforts on startup performance (like the work Apple did with Java 1.5, which was built upon Hotspot).

But things are improving. JVMs that used to take ten or more seconds to start up may now take well under a second. That was unheard of 5 years ago. Additional work going into OpenJDK 7 and OpenJDK 6 updates promise to improve this further, and future research may even help reduce the warmup time required for maximum performance. Projects like JRuby have helped drive this work forward.

And we also understand the pain that slow startup can cause users. With each release we spend some time looking for ways to improve JRuby’s startup. Indeed, we even use slower JVM settings by default because we want the user experience to be better (specifically, we try to force Hotspot-based JVMs to use the faster-starting but less-optimized “client” VM, with switches to turn on the optimizing “server” VM). With JRuby 1.3, we started shipping support for “Nailgun”, a persistent background JVM you toss commands at (in order to reduce the spin-up and warm-up time for quick commands). There’s more work to do, but we feel users’ pain, and try to address it better with each release.

Macs ship with a JVM, it’s readily available for Linux distributions via packages, and a number of Windows machine vendors have it pre-installed nowadays. Despite that, a number of Rubyists somewhat disregard JRuby for having any relationship whatsoever to Java. Are they throwing the baby out with the bathwater?

They certainly are, but we also accept that JRuby isn’t for everyone. Maybe the startup time is a show-stopper. Maybe it’s JRuby’s less-than-perfect support for exact POSIX IO and subprocess behavior. Maybe it’s the lack of support for C extensions. There are certainly reasons why JRuby wouldn’t be the best choice for certain problem domains. But there’s also tremendous potential for JRuby to bring Ruby to problem domains, organizations, and platforms that it might never have been able to reach. JRuby opens up a huge world of opportunity for Rubyists and brings Ruby to the huge world of JVM-based developers. It’s such a beautiful match that I spent 20-30 hours per week on JRuby for almost a year before being hired by Sun … all in my spare time, because I was so excited about the possibilities.

What really depresses me is that many of the folks dismissing JRuby are exactly the folks who could help us make Ruby a better option for developers on the JVM. We need Rubyists skilled in building DSLs, skilled in designing libraries, skilled in integrating systems. We need day-to-day Rubyists to show Java developers how much better things could be for them. We need the amazing Ruby community to help us bring Ruby to a much larger world. There’s no time for platform bigotry … we all want the same thing: Ruby everywhere!

What can you tell the common Rubyist about application platform layers like the ones provided by Torquebox and Glassfish?

Both Torquebox (JBoss’s set of excellent Ruby wrappers around key server-side Java APIs and tools for deploying JRuby on Rails applications) and GlassFish (Sun Microsystem’s modular Java-based server, with lightweight “embedded” JRuby deployment support and a few similar API wrappers) are examples of how the best parts of the Java/JVM ecosystem can be repurposed (and improved) using a little Ruby knowhow. In both cases, you get simple, one-shot deployment (of multiple applications, I might add), along with well-designed service APIs and management tooling.

We would love to see the “Torquebox approach” or the “GlassFish way” applied to other popular Java APIs for persistence, networking, web services, and more. We’ll try to tackle some of the key libraries ourselves, but again we need help from the Ruby community. And in return we’ll promise to faithfully support Rubyists and to continue improving JRuby.

Github used JRuby to allow for code obfuscation and I’m assuming to best integrate with the kinds of customers who would pay for it. Do you see this type of decision making driving JRuby adoption as Ruby becomes more commonplace in the enterprise?

As long as there’s demand for Ruby, there will be demand for features unique to JRuby like easy deployment on Java services and compiled “obfuscation” like the Github folks needed. And these are only the beginning. JRuby can make it possible to write Ruby-based Android applications. JRuby can produce fully-compiled desktop applications in a single executable file that runs wherever there’s a standard JVM. JRuby can integrate easily with other JVM languages and access the vast world of JVM libraries. And it can do all this while still being true to Ruby.

All we have ever wanted is for JRuby to be a powerful, useful tool for JVM users and Ruby fans alike. And anyone who has talked to us knows we put the needs of our users first. Why not become a JRuby user today?

Gartner Inc. predicts that Android will make up 14% of the smartphone market in the year 2012, second only to the Symbian OS that powers some popular Nokia phones. What can you tell us about working with Android via JRuby?

It’s still early days for “Ruboto” (JRuby on Android), but there’s a lot of potential. I’ve been hearing from a few people every week interested in using Ruby as their Android language of choice, so the demand is certainly there. And with the Android 1.6 and 2.0 updates, JRuby appears to work fully on Android without any modifications.

For an early example of what’s possible, check out my ruboto-irb project on Github (link), which is basically an interactive Ruby session that runs directly on the device. You can do everything you would normally do with Ruby in IRB, plus construct and call Android core classes. It’s great fun, and with a bit more work I could see JRuby being ready for production use on Android.

Recently I’ve noticed some dialogue with regard to JRuby and Maven. I’ve seen references to Maven v3, and also to “Polyglot Maven.” Can you shed some light on the implications of this new interoperability for the everyday JRubyist?

There are two projects for JRuby and Maven integration.

The first is a prototype Maven server that looks and feels like a RubyGems source. By setting this server as a source (or passing it to the gem command), any Java library in the world is installable as a gem. Let me repeat that: ANY Java library in the world, installable as a gem. This means you can also use Maven artifacts as dependencies in regular Ruby gems, and it additionally means we won’t have to re-release jar files into their own duplicate gems on the standard repositories. It’s very exciting, and we hope to have it ready for JRuby 1.5.

The second project is part of the official “Polyglot Maven” work started by Jason van Zyl and the Sonatype folks. That project intends to provide standard DSLs for popular JVM languages, allowing you to use those languages in place of the XML-based POM files so many people hate. In addition, those DSLs would have access to Maven’s workflow and data model classes, providing fully-scriptable Maven builds without a lot of the noise of a typical Maven project. This work is still in early days for JRuby; I’ve only committed a couple prototype scripts to the repository. We would love to have help here, since we’re not really Maven experts.

Generic Q/A

There are ~150 native extension gems for Ruby, some of which are prolific and often depended upon by other gems. Does your Ruby implementation support FFI (foreign function interface) at present, and/or how much of a priority is running native extension gems going forward?

I believe that native extensions are the #1 thing holding the standard Ruby implementation (MRI) back. If you look at archives of the Ruby mailing lists going back for years, maintaining extension compatibility has always come at the expense of improving MRI. You want a better GC that’s generational and compacting? Sorry, that wouldn’t be compatible with current extensions without a big performance hit. How about real concurrent threads? Nope, without adding fine-grained locks or safepoints around all extension calls, you’re sure to segfault somewhere.

JRuby does support FFI, and has for well over a year now. In fact, Wayne Meissner of the JRuby team is largely responsible for FFI being a viable alternative to C extensions, since he implemented the FFI gem for MRI and has been working closely with the FFI community ever since. We believe FFI, or mechanisms like it, are the best way to call C libraries from Ruby, regardless of the implementation, and we encourage people to use FFI if there’s a native library they simply must use.

As far as real native extension support… anything’s possible, but we have no plans to support MRI’s C API in JRuby. The API is unfortunately very invasive, giving direct memory access to object internals in many places. In order to support this on JRuby, we would need to copy lots of data back and forth on every call, not to mention locking down extension calls per-thread completely to ensure they weren’t stepping on each others’ data. It might be possible to get a limited subset of the MRI extension API implemented for JRuby, but existing extensions would require some rework and performance would probably end up worse than FFI due to the amount of copying and locking required.

In general, the only 100% answer for JRuby is to port extensions to a JVM language or wrap existing JVM libraries (and there are literally tens of thousands of libraries available). FFI provides a good stopgap or bandaid for the problem, but it still requires us to load a native library which many deployment environments will disallow. Only pure-“Java” libraries (where by “Java” I mean “some JVM language”) will have the best possible chance of running on all target systems.

Passing RubySpec tests is fundamentally important. Has this compliance lowered the theoretical performance ceiling of your implementation considerably?

Ruby is a difficult language to implement. JRuby is arguably the only production-quality alternative Ruby, and that quality has come after literally dozens of man-years of work. We’ve also managed to achieve production-level compatibility while turning JRuby into one of the best-performing implementations, so we have a solid understanding of the challenges involved.

There’s no doubt about it: Ruby has lots of features that make optimization really hard. Being able to use a block as the binding to an “eval” call forces us to keep all of the block’s surrounding state, even if the block itself doesn’t need it. Backref and lastline references ($~ and $_ variables) require a called method to be able to modify the caller’s context, even if the method itself never accesses those values. The ability to replace methods on core classes – even super-important ones like Fixnum#+ – means we have to always check for those modifications. Even simple things like “eval” and “send” force us to deoptimize more code than we’d like.

We have managed to work around many of these challenges, just like some of the other Ruby implementations, but many of them remain. In almost every case, we’ve tried first to get solid compatibility, optimizing later as much as we can. We plan to revisit those performance challenges in the future, learning from other dynamic language runtimes and other Ruby implementations about new ways to optimized. But right now we’re pretty happy with JRuby’s performance, which puts us at least on par with Ruby 1.9 for almost everything (and faster for many things).

Closures, continuations, and tail-call optimizations are often discussed in terms of programming language VM’s. Which of these attributes are implementable at present, which are expected to be implemented, and which are not possible by design?

Closures are probably the easiest one. If you can save some local context and pass it around with a function reference, you’ve got closures. There’s plenty of details, like making non-local flow control work (break or return inside a block), but in general they’re not difficult to support.

Continuations and tail-calls unfortunately both require VM-level support to do well.

JRuby does not support Ruby’s continuations because the JVM does not (yet) support continuations. In order for us to implement continuations atop the JVM, we would have to forgo standard Java method dispatch for all of JRuby, since any calls that would deepen the stack would make saving a continuation impossible. The performance impact of this would be tremendous: the JVM gets its performance because it’s able to optimize normal chains of calls; by trampolining in and out of methods at the same stack depth, practically none of the standard optimizations would fire. We actually did try a “stackless” implementation in 2005, and I demoed it at RubyConf that year. It could calculate a recursive fib(1_000_000), but it ran so incredibly slow (orders of magnitude slower than what we have right now) that it simply wasn’t feasible.

For tail calls, VM support is necessary to do a 100% job, but you *can* fake some recursive tail-call optimization by branching back to the top of a method body. We have not implemented any “tricky” tail-call optimization yet, but it’s a possibility for future versions of JRuby.

And in both cases, there’s some interesting work on the horizon. Both tail calls (“true” tail calls) and continuations are being developed against the Multi-Language VM subproject of OpenJDK, and both actually have working patches right now. There’s a good chance that a future version of the JVM will have support for true tail calls, and a slim chance that delimited continuations (coroutines) might arrive as well. That’s part of the beauty of JRuby: there’s dozens or hundreds of JVM engineers out there working to make it faster, working to add features, and competing with each other. JRuby users directly benefit from all that work.

How integral is dynamic feedback-based optimization to reaching a high level of performance? Do you feel it will be possible to maintain acceptable speed into the future without embracing these strategies or are there less well-known alternatives which are potentially more effective?

Because we run on the JVM, we already benefit from a tremendous amount of runtime optimization. JRuby’s core classes (Hash, Array, etc) are perhaps the fastest implementations of any Ruby, largely because they’re all written in Java and benefit from the very best JVM optimizations available. At the end of the day, the vast amount of Ruby execution is in the core class implementations, so they really need to be as fast as possible, and Java is our “C” for doing that.

We also benefit from feedback-based optimization when running Ruby code, though we still have a lot of opportunity here. Currently, JRuby’s Ruby compiler is fairly “dumb”: it doesn’t use runtime profiling *at all* and only does a few limited static optimizations. Now of course the JVM is able to pick up a lot of slack, using its own runtime profiling to make our “dumb” generated code run really well. But because we recognize that we need to help the JVM out a bit more, we do have plans to introduce more runtime feedback into our Just-In-Time compiler subsystem. Expect to see more work on JRuby performance in 2010.

There’s also a Java 7 feature we’ve started to play with: fast dynamic invocation. JSR-292, the “invokedynamic” JSR, is adding a new bytecode called “invokedynamic” to the JVM. The invokedynamic bytecode allows us to wire up (for example) Ruby method invocation directly into the JVM’s call protocols. As a result, the JVM can do all its usual inlining and optimization even across Ruby calls. Early results have been promising… even without a lot of optimization, the current invokedynamic implementation is 20-30% faster than our old call protocols. We’ve been working closely with Hotspot engineers throughout their development, and we’re really looking forward to seeing how well JRuby runs on invokedynamic in the coming months.

Which of 1.8.7 and 1.9.x is your implementation compatible with?

JRuby 1.4 made the move to Ruby 1.8.7 compatibility, because we felt that 1.8.7 has become established enough (and because we were tired of getting bug reports about 1.8.7 features being missing). We also have done a lot of work on supporting Ruby 1.9, though that’s still a bit of a moving target. We’re hoping that in the first half of 2010 we’ll be able to reach feature-parity with the upcoming Ruby 1.9.2. We’ll definitely need help from the community.

Do you think further acceptance of Ruby is driven equally by spending man-hours working on performance and by meeting an international body’s specification?

I think performance is somewhat of a red herring, and as I mentioned before it can be a tremendous resource sink. We will, just like the other implementations, continue incrementally improving performance. But given JRuby’s unique features, our current level of performance is good enough for us to focus on other areas for a while. We won’t ignore performance, and we don’t want to fall behind in the endless performance wars, but we have to balance features, compatibility, and stability at the same time.

As far as specification goes… I think it’s only useful for entities that require specifications. If it’s true that many organizations worldwide will refuse to adopt Ruby due to a lack of a specification, then time spent preparing such a specification is probably worthwhile. Since there’s already such an effort, I sincerely hope it will help increase Ruby adoption.

What are your team’s goals for the next quarter, the next year?

The number one goal for me is Java integration. Java integration means many things:

  • ability to generate *real* Java classes for Ruby classes, both at runtime and ahead-of-time
  • fast-as-possible Ruby-to-Java invocation
  • ecosystem integration, like our recent work to make all Maven artifacts in the world transparently installable as gems
  • platform integration, like making Rails work naturally as a Java-land web framework, and making Java-land frameworks like Hibernate fit naturally into Rails

I also want to return to performance work, most likely by continuing the work that Subbu Sastry has already begun on JRuby’s new optimizing compiler. The potential here is to do a large amount of optimization before feeding bytecode to the JVM, allowing us to approach the performance of statically-typed languages over the same code. We want to make Ruby run as well as possible on the JVM, and I think the new compiler work will be a big part of that.

Besides any obvious platform niche, why might someone benefit from electing to use your Ruby Implementation?

Well, we’ve got several years of production users under our belt! The value of having real users for several years can’t be understated, and we learned very quickly that getting a 1.0 release out is just the beginning.

JRuby Installation

If you’ve still not given JRuby a proper try, you can learn more at the official JRuby site or if you’re using the RVM (Ruby Version Manager) you can be up and running on the latest main build (1.4.0) with:

rvm install jruby

Recent Confreaks Presentations

You can watch the full keynote “JRuby State of the Union” by Charles Nutter and Tom Enebo here at Confreaks’ site or you can go directly to the video (MPEG 4) file here.


During their respective funding periods, Sun and Engine Yard have both had a strong commitment to JRuby. For Ruby to thrive, it ultimately needs to be deployed in numbers that achieve a lasting critical mass. There is a reportedly massive amount of existing infrastructure based on the JVM, which makes JRuby a noteworthy stepping stone to many interesting destinations, and based on what we’ve discussed here, why would anyone obstinately ignore JRuby any longer?

Pancake: How To Stack and Loosely Couple Rack-Based Webapps Together

stack-o-pancakesMuch of Merb’s momentum has been merged into Rails 3, but one-time Engine Yard developer Daniel Neighman has found himself moving in a new direction, inspired by what they had once achieved with Merb Slices. Since then, he’s taken fully-mountable Rack applications to the extreme in creating Pancake, a tool & framework to let you stack and loosely couple Rack-based webapps.

Daniel states that web “applications should be self contained rack applications, able to function as gems, able to pick up an entire application and mount it inside another, able to inherit the whole application and take care of the low level plumbing,” and also “let you create your own type of application when required.” Pancake achieves this by building upon some excellent existing projects, including Tilt for templating, Usher for routing, and Hashie to extend the features of Ruby’s hashes and give them additional object-like functionality.

Joining Apps With Rails (And Each Other..)

Yehuda Katz was first seen using Usher in his blog entry How to Build Sinatra in Rails 3 and it is being used for developing Pancake guaranteeing that anything you build with it is going to be mountable in Rails 3. Pancake stacks can be used with the current versions of Rails via Metal, and examples are given on Pancake’s blog for doing so.

Sinatra apps are mountable through Pancake, as are any other fully Rack-compliant parts, and Rack middleware can be applied to either the entire Pancake stack, or to individual stacks within the container app. One can first make gems of stacks, which can then be inherited by their containing app or stack. While this sounds like it could become messy quickly, Pancake employs namespacing to keep everything distinct.

Installation and Usage

To get started with Pancake, I ended up installing via:

sudo gem install usher rake pancake haml rcov rack-test rspec racksh

I then created a stack by issuing:

sudo pancake-gen short ri_example    ## pancake-gen {short || micro} 

To move further, check out two projects: Pancake Blog (mountable basic blogging) and CouchDB Proxy (mountable couchdb proxy)

Rango: A New Modular Ruby Webapp Framework

Screen shot 2009-12-02 at 13.25.25Rango is a Rack-based lightweight Web framework by Jakub Šťastný that has seemingly borrowed a little bit less from past Ruby frameworks and a bit more from Django. Based on the 1.9 version of Ruby, Rango works with rvm, Rip, Usher, Warden, and both the new Gem bundler and the venerable DataMapper by default.

Philosophically, “Rango is attempting to be as agnostic as possible, valuing simple, readable code.  It intends to encourage explicit code rather than implicit magic.”  Modularity is a top priority. In many ways it feels like Ramaze, but with a newer “era of Rack” foundation. There’s a good “Why Use Rango” article available if you want to get a feel for the project and why you might consider using it. There’s also a PDF presentation that acts as an introduction to the project.

Serving, Routing and Templates

Rango is Passenger friendly, and because Rango is designed for Ruby 1.9, using Mongrel is discouraged (although possible).  The router is pluggable and Usher is the default, but you can elect rack-router or rack-mount via the generator.  At present, Rango plays nicely with Haml, but with the upcoming 0.2 version it will adopt Tilt, which adds a number of formats, including Mustache, ERB, Erubis, and Liquid.

Rango has generators, but beyond that it employs a sub-project named “Simple-Templater” to assist developers in customizing project-specific code generation. Rango draws additional strength from “Pupu,” a framework agnostic CLI (command-line interface) system which aids in managing /public directory content and functionality into modules – modules which can even include packaged javascript functionality.

Code reloading during development is made available by Shotgun, or if you are using Phusion Passenger, you can of course use tmp/always_restart.txt to restart the app at every request. If Racksh is installed, running ./init.rb -i will start it, and it falls back to Irb otherwise.

The Future

Rango has a very aggressive roadmap for December 2009, and also boasts an impressive feature timeline within the wiki.  Rango offers a number of innovative departures which seem noteworthy at present.  To get updates on the Rango project, follow @RangoProject on Twitter.

caliper-logo.png[ad] Find duplication, code smells, complex code and more in your Ruby code with Caliper! The metrics are free and setup takes just one click. Get started!