Why MacRuby Matters (Present & Future)

HotCocoa::Graphics exampleOver the years the inadequacy of Ruby’s main implementation has led to the creation of several alternatives. The greatest common divisor between these is an attempt to improve the performance of Ruby, both in terms of time and space. But every Ruby implementation has another, deeper reason for being. For example, Ruby 1.9.1 is a refactoring of the language that provides the chance to incorporate several much needed features into a relatively fast virtual machine, whereas JRuby’s truest value lies in its ability to interact with the Java ecosystem. Likewise IronRuby (which is admittedly at an earlier stage in its development) is attempting to plug a dynamic language like Ruby into the .NET world (as per its predecessor IronPython).

While MacRuby is a younger, lesser known implementation, it has the potential to become a game changer – at least for Mac developers. Based on Ruby 1.9, MacRuby’s main aim is to provide programmers with the ability to write Mac OS X applications in Ruby, making Ruby a first class Cocoa programming language. In what may sound like an utopistic effort, MacRuby strives to provide the high level abstractions, power and syntax sugar of Ruby, without the characteristic performance hit of its main implementation.

Rather than relying on a mix of Objective-C and Ruby (through a bridge like RubyCocoa), developers can use MacRuby which integrates with Mac OS X core technologies and acts as an alternative language to Objective-C. To be exact, Objective-C’s runtime and generational garbage collector are at the heart of MacRuby, but from an API standpoint, programmers can write code in Ruby, instead of in the more verbose and low level Objective-C. MacRuby maintains the ability to integrate with Objective-C code, but doing so is often unnecessary thanks to a framework known as HotCocoa, which is a Ruby wrapper around the Cocoa API.

MacRuby applications end up being succinct, easy to write and straightforward to maintain. Their look and feel is exactly the same as those of applications written in Objective-C, because they are actually native Cocoa applications. In fact, MacRuby objects are Objective-C objects which use Core Foundation data types and services. The current version, MacRuby 0.4, even allows you to package applications as self-contained .app, without having to redistribute MacRuby itself.

Sponsored and developed by Apple, MacRuby 0.4 is a stable release that can be – and already is – used to write desktop applications. But MacRuby’s real promise lies in its experimental branch. This rewrite will become MacRuby 0.5, as announced by the MacRuby team earlier today (along with a new, nice looking site). This future version of MacRuby is freakishly fast and uses the LLVM to generate code for the Objective-C runtime. The layer composed of LLVM, ObjC Runtime, Generational Garbage Collector and Core Foundation make this specific Mac OS X release possible. To this layer, add in Ruby 1.9’s AST parser and Standard Library, and you get MacRuby 0.5 as it stands today. In the future it’s likely that applications built with MacRuby will be compiled into binary code, like Objective-C ones, thus removing the issue of protecting one’s source code in commercial applications.

To really understand the value of MacRuby, consider the following Hello World program that uses RubyCocoa:

require 'osx/cocoa'; include OSX

app = NSApplication.sharedApplication

win = NSWindow.alloc.initWithContentRect_styleMask_backing_defer(
    [0, 0, 200, 60],
    NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask,
    NSBackingStoreBuffered, false)
win.title = 'Hello World'

button = NSButton.alloc.initWithFrame(NSZeroRect)
win.contentView.addSubview(button)
button.bezelStyle = NSRoundedBezelStyle
button.title = 'Hello!'
button.sizeToFit
button.frameOrigin = NSMakePoint((win.contentView.frameSize.width / 2.0) - (button.frameSize.width / 2.0),
                                 (win.contentView.frameSize.height / 2.0) - (button.frameSize.height / 2.0))

button_controller = Object.new

def button_controller.sayHello(sender)
 puts "Hello World!"
end

button.target = button_controller
button.action = 'sayHello:'

win.display
win.orderFrontRegardless

app.run

And compared to the equivalent MacRuby and HotCocoa program:

require 'hotcocoa'
include HotCocoa

application do |app|
 win = window :size => [100,50]
 b = button :title => 'Hello'
 b.on_action { puts 'World!' }
 win << b
end

The first approach reminds me of Objective-C, the second is a pure Ruby DSL.

Benchmarking the experimental branch

The question on many readers minds is probably, how fast is it? To begin with, the start-up time is negligible which is a good quality for desktop applications to have. Using the YARV tests that ship with the experimental branch, let me show you the numbers I obtained on a Mac Pro with two Quad-core Intel Xeon 2.8 GhZ and 18 GB of RAM. The tests were also run on much less “beefier” hardware with analogous results.

All the usual disclaimers apply here. These are just a few very basic micro-benchmarks that should give you a “feel” for how two VMs stack up against each other; but don’t read too much into this and don’t expect it to be a scientific report on the performance of the implementations that were tested. Also keep in mind that MacRuby 0.5 is currently an experimental release, and while it’s able to pass RubySpec’s language specifications, it is not a complete implementation so far. The team is taking incompatibility issues seriously though and will make sure MacRuby will be able to run any Ruby code.

The following table summarizes the results of these benchmarks for Ruby 1.8.6, Ruby 1.9.1 and MacRuby 0.5:

MacRuby table1

This table shows the ratios between Ruby 1.9.1 and MacRuby 0.5, respectively, against the Ruby 1.8.6 baseline. When you see a number 4, for example, that means that the given implementation was four times faster than Ruby 1.8.6.

MacRuby table2

And here is a direct comparison between Ruby 1.9.1 and MacRuby 0.5. In this case, a number 4 (for example) would mean that MacRuby was four times faster than Ruby 1.9.1 for the given test:

MacRuby table3

The following chart should help you better visualize the results shown in the first table (click on it to enlarge the picture):

MacRuby chart

Even when you consider the disclaimer above and the trivial nature of the benchmarks themselves, it’s clear that at this stage of the game, MacRuby 0.5 is built for speed. the fastest Ruby implementation around. MacRuby literally dominates Ruby 1.9.1. On “average”, according to these limited tests the experimental branch of MacRuby appears to be roughly 3 times faster than Ruby 1.9.1 (YARV), and in some cases even faster than that. You should definitely find this impressive.

For full disclosure, I’d like to explain the most likely reasons behind the four tests in which MacRuby is slower than Ruby 1.9.1:

  • bm_app_raise: MacRuby opts for cost free IA64 exceptions. What this means is that begin/rescue clauses don’t require a setjmp() like YARV does, but in case of exceptions at runtime, raising an error is more expensive. Of course, exceptions are… well, exceptional, so this has a trivial impact on real world programs.
  • bm_app_mergesort: Array operations are currently suboptimal. Slight improvements are expected.
  • bm_so_object: MacRuby’s object allocation tends to be relatively expensive. If you are allocating a zillion objects in a test, MacRuby will pay a hefty price for it.
  • bm_so_random: The performance of Fixnum has been optimized in this early release, but both Bignum and floating point operations are still suboptimal. Work is in progress and major improvements are expected to occur in future versions. In the case of Bignum, vectorization will do the trick.

The take home lesson

MacRuby is a serious project that fits in, and serves the flourishing market of Cocoa applications well. Its experimental branch is a major rewrite that, grants this implementation the title of fastest Ruby in the West that, much like Unladen Swallow for CPython, could become a very fast alternative to Ruby 1.9.x and JRuby. It’s mainly aimed at the desktop world, and as such the question of when it will work with Rails, is less pressing than it was in other early Ruby implementations. What’s certain is that Ruby is going to become a first class “scripting” language and a common choice for desktop applications on Mac. And should the difference in performance still remain in future, stable versions, it’s not hard to imagine that Apple’s server segment could also benefit from this, when Rails support becomes available.

Update (2009-04-04): I’ve modified a controversial statement since, technically speaking, while it is true that a very fast, incomplete implementation is promising and worth getting excited about, it cannot be considered the fastest Ruby implementation until a great degree of compatibility has been reached. This doesn’t diminish the value of MacRuby in any way, but rather draws a more accurate conclusion about the data that’s available today. It’s also worth noting that the few benchmarks that have been mentioned here are only part of the story. Speed aside, MacRuby’s aim and potential for Mac development still stand.

The image at the top of the post was generated by James Reynolds with HotCocoa::Graphics, a Processing-like library that uses Mac OS X’s graphics capabilities and makes them available to MacRuby.

Get more stuff like this

Subscribe to my mailing list to receive similar updates about programming.

Thank you for subscribing. Please check your email to confirm your subscription.

Something went wrong.

36 Comments

  1. Matt Aimonetti March 29, 2009
  2. Charles Oliver Nutter March 29, 2009
  3. Tyler Arrigoni March 29, 2009
  4. Patrick Thomson March 29, 2009
  5. dave March 29, 2009
  6. Jason March 29, 2009
  7. Craig Buchek March 29, 2009
  8. Brian Cardarella March 29, 2009
  9. Antonio Cangiano March 29, 2009
  10. Richard Kilmer March 29, 2009
  11. Mark Allerton March 29, 2009
  12. Laurent Sansonetti March 29, 2009
  13. Antonio Cangiano March 29, 2009
  14. Ninh Bui March 29, 2009
  15. Ted Han March 29, 2009
  16. Matthijs Langenberg March 29, 2009
  17. Richard Wekson March 29, 2009
  18. zizo March 29, 2009
  19. David Parker March 29, 2009
  20. Matt Aimonetti March 29, 2009
  21. Jason Ozolins March 30, 2009
  22. asdcascasa March 30, 2009
  23. Robert Sheehan March 30, 2009
  24. Gavin Kistner March 30, 2009
  25. Charlie Hayes March 30, 2009
  26. JulesLt March 30, 2009
  27. Kurt Stephens March 31, 2009
  28. Pingback: MacRuby Marches Onwards April 1, 2009
  29. Kurt Stephens April 1, 2009
  30. Preston Holmes April 1, 2009
  31. Thomas Davie April 2, 2009
  32. Antonio Cangiano April 2, 2009
  33. Pingback: O MacRuby Avança April 3, 2009
  34. Pingback: LLVM’s growth April 5, 2009
  35. roger pack April 20, 2009
  36. Pingback: a JIT for ruby! « Roger’s Brain Dump April 20, 2009
  37. roger May 4, 2009
  38. Daniel December 16, 2009
  39. Robert March 10, 2010
  40. Robert March 10, 2010

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.