The Planks in the Bridge

February 16th, 2007

So. C is taking the new role of assembly language. We used to rewrite C snippets in assembly to speed it up, now we rewrite other code in C to speed it up. Fierce discussion around this premise has broken out, and at least some credit yesterday’s Take it to the Bridge for helping spark that discussion. That’s incredibly interesting, since it was only part of my message. I feel the real message about the bridges needs some clarification.

The big ideas with the shift from the Java bridge to the Python and Ruby bridges is this:

  • Python and Ruby are both more dynamic than Objective-C, not less.
  • Python and Ruby can adopt many techniques that Java could not.
  • Python and Ruby can both call into C.
  • Python and Ruby does not need .jobs files.

Java is notoriously more static in Cocoa than Objective-C is. Java could not ever, say, adopt Key-Value Observing (KVO). KVO is part of a two-part tag team with Key-Value Coding (which is available in Java). KVC means that instead of writing NSString *str = [[[foo bar] baz] quux], you can write NSString *str = [foo valueForKeyPath:@"bar.baz.quux"]. Who in their right mind would want to do that? Well, in combination with KVO, anyone wanting to use a kick-ass bindings system, that’s who.

KVO means that you can get notified, you can ‘observe’ when something changes somewhere. For this to happen, code needs to be swapped in. This happens through “isa-swizzling”. That’s short for “Objective-C implementation magic which is impossible in Java and easy in both Python and Ruby”.

Also, class posing and its cadre of friends? Implementation magic in Objective-C, impossible in Java, easy in Python and Ruby. (“Thanks to the Aperture Science Portal device, the impossible is easy.”)

Furthermore, both PyObjC and RubyCocoa use Libffi – a library for calling C functions in an uncharacteristically dynamic way, similar to modern method invocations.

And let’s not forget external metadata. Users of the Java bridge have to painstakingly map every method call and data type to their Java counterparts. (Specified in a .jobs file; supposedly that means “Java to Objective-C Bridging Specification”, but I think it means “the last name of the guy the team behind the Java Bridge wanted to secretly kill on those 10 PM Friday nights”.)

Meanwhile, the RubyCocoa preview release details a process in which a framework called BridgeSupport is used:

RubyCocoa used to handle the C bits of frameworks by parsing the headers and generating some static code at build time. But this became hard to maintain as you have to rebuild the bridge to support a new framework. Thus the idea to modify Rubycocoa to be metadata-driven. Instead of generating static code, we generate metadata files and RubyCocoa interprets them at runtime.

We have a metadata generator that is ran at build time to produce metadata information for a set of default frameworks. The metadata format is XML. We generate a file per framework. Metadata describes C functions, enumerations, constants, structures but also opaque and CoreFoundation-based types, and Objective-C informal protocol methods. The metadata also provides a better description of methods returning a boolean value and accepting pointer-like arguments.

The RubyCocoa preview also notes that: “Thanks to the new metadata mechanism we are now able to bridge frameworks more easily than previously.” Java only ever got a few frameworks beyond AppKit and Foundation; it didn’t get WebKit and it didn’t even get AddressBook. For Java you had to hand-edit a file and write a corresponding interface – for Python and Ruby, you get it for free at the cost of some build-time interspection.

To wrap up: The team at Apple behind this not only looks set not to repeat the pitfalls of the Java Bridge, it even looks like they’re ready to invent some common ground again.

The Python and Ruby bridges could turn out the best thing that has happened to Cocoa development in a very long time.