|
This post originated from an RSS feed registered with Ruby Buzz
by Laurent Sansonetti.
|
Original Post: ruby+objc, Part 1
Feed Title: lrz's diary
Feed URL: http://www.chopine.be/lrz/diary/xml/rss/feed.xml
Feed Description: lrz's diary
|
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Laurent Sansonetti
Latest Posts From lrz's diary
|
|
I have recently been working on a new project, called for the moment ruby+objc (I know I need a better name), and it's now time to write a little about it.
ruby+objc can be seen as a new flavor of Ruby that runs on the Objective-C runtime. It's basically a modified version of the existing Ruby 1.9 branch. This is something I wanted to do since a little less than 2 years now, but Ruby 1.8 was not suitable. And of course I didn't want to re-invent the wheel.
$ /usr/local/bin/ruby -v
ruby+objc 1.9.0 (2007-12-06 patchlevel 0) [i686-darwin9.0.0]
It basically behaves as the normal Ruby 1.9. For instance, all meaningful tests included in the 1.9 distribution are passing.
Speaking about the implementation, all Ruby classes are actually Objective-C classes, modulo some bits that need to be kept separately. To avoid conflicts, Objective-C class names are prefixed by RB. The same exists for existing Objective-C classes, that are imported into Ruby at demand.
NSObject is the root class of all Ruby objects.
$ /usr/local/bin/ruby -e "p String.ancestors"
[String, Comparable, Object, NSObject, Kernel]
But to really discover the changes, let's start gdb:
$ gdb --args /usr/local/bin/ruby -v
[...]
(gdb) po rb_str_new2("foo")
<RBString: 0x19cd60>
As you can see, a Ruby String object is in fact an Objective-C object of the RBString class. And it responds to the -[NSObject description] method, which is evident since NSObject is now an ancestor of RBString.
(gdb) po [NSObject new]
<NSObject: 0x278080>
(gdb) po rb_ary_new3(1, 0x278080)
<RBArray: 0x19cd44>
(gdb) p ((struct RArray *)0x19cd44)->len
$4 = 1
Pure Objective-C objects can be passed into Ruby without any problem. As an example, we add a pure NSObject object into a Ruby array. (Note that the RBArray Objective-C object can be casted as an RArray C structure.)
But there is more.
(gdb) po [0x19cd44 last]
<NSObject: 0x278080>
Since Ruby classes are actually Objective-C classes, their methods are also exposed in Objective-C. Here, we call Array#last by sending the Objective-C last message to the object, and we get the same identical pure NSObject object that we created earlier.
(gdb) po rb_funcall(0x278080, rb_intern("to_s"), 0)
<RBString: 0x19cc80>
(gdb) p ((struct RString *)0x19cc80)->as.heap.ptr
$8 = 0x278520 "#<NSObject:0x278080>"
And reciprocally, we can call the Kernel#to_s method on our pure NSObject object, and it returns a valid Ruby string object. It works because the Kernel module is included in NSObject, and that the Objective-C methods are exposed in YARV.
That's enough for today, but to resume the big ideas, Ruby classes are Objective-C classes; methods are exposed in both languages; Ruby objects are Objective-C objects; and Objective-C objects can be used directly in Ruby. Proxy objects and caches are abolished! Everything is very straightforward, and according to a few micro-benchmarks that I made, it's around 10 times faster than RubyCocoa.
Stay tuned for more details, especially on garbage collection.
Read: ruby+objc, Part 1