« RubyCocoa progress | Main | Analysis of RubyCocoa's internals »

February 19, 2005

Quick ports with RubyCocoa

I ported my Objective-C audio app to RubyCocoa this afternoon, so now I've got a better feel for its pros/cons.

The method calls from the Ruby side are fairly similar to the native Objective-C calls, so in most cases, you can read the Apple docs for different classes and write corresponding Ruby calls on the first try.

Let's say you started developing your app with a NSView object that displays dvd video, and wanted to add a transparent view on top of it so you can show subtitles without a lot of fuss. In order to add the subview to your view, the Objective-C call would look like:

[dvdView addSubView:subview positioned:above relativeTo:otherView];

Calling the same method from ruby looks like this:

dvdView.addSubView(subview, :positioned, above, :relativeTo, otherView);

RubyCocoa provides other ways to mimic ObjC's selectors with Ruby method calls, but this technique is closest to the Smalltalk selector syntax that Cocoa uses. It makes porting the calls from the Apple docs easier IMO.

One of the big things I learned today is that you want to keep any NSView-like classes in Objective-C if possible. For example, NSView's drawRect method is called whenever you need to redisplay a view. The app I wrote has two 512x201 views that display audio data, with a slider attached to the pair of them to let users move around the sample set quickly. The redraw is snappy with a native Cocoa app, but RubyCocoa ends up being slow because the AppKit calls are going through the Ruby <-> Objective-C bridge.

The bridge delay is usually okay because in most cases, you're loading data periodically and setting controls and views in your window without doing any kind of continuous processing. When you're drawing a view though, your drawRect method could be called dozens of times a second. My Objective-C drawRect completes in a 3-5 milliseconds, but the Ruby one takes about 150 milliseconds. That's quite a performance difference!

The performance differential isn't a big deal for me since my major use of RubyCocoa is going to be for prototyping applications and deciding how their structure and business logic will work. RubyCocoa co-exists well with Objective-C controller/model/view classes, so it's not hard to implement time-critical classes in Objective-C.

My slides are about half-done, and I've got the audio app plus a skeleton framework ready for the live hacking on Thursday night. I was even able to add some features that the Objective-C app doesn't have yet! Ryan and I were chatting tonight about packing/unpacking of binary values, and we talked about RC and the preparations I'm making for the talk. The more progress I make, the more excited I get to give it, I think it's going to go well.

Once I finish the slides tomorrow morning, I'm going to spend some time on figuring out how to bundle ruby's extensions and libraries into RubyCocoa apps. I think a completely self-contained app would be cool, and bundling a ruby interpreter with full libs only adds 10MB to the app size, and nothing to the memory footprint. A fully contained app would also mean you had full control over what ruby libraries and versions were being used, so it would make the apps more reliable and remove the dependency on user installation and tweaking of external software and libraries.

Posted by djb at February 19, 2005 09:21 PM

Comments

Post a comment




Remember Me?

(you may use HTML tags for style)