How Does MacRuby Work?
Clone this wiki locally
This page collects various implementation details about MacRuby. For a user-friendly description, with examples, please see the MacRuby Tutorial
Note that since MacRuby is still under development, the content of this page may not always be up-to-date.
Class and Object Model
Ruby classes in MacRuby are in fact Objective-C classes. Because it is not yet possible to completely express the Ruby semantics with the Objective-C runtime, some extra bits are still being allocated per class. For example, Objective-C doesn't allow instance variables to be added at runtime to a class, or classes to be nested, so MacRuby has to work around that.
Every method defined on a class from Ruby is registered with the Objective-C runtime. On a similar note, all Objective-C methods are lazily available from Ruby too. The Libffi library is used to create closures at runtime and inject them, either in the Objective-C runtime or YARV, but also to perform C or Objective-C calls.
All Ruby classes inherit from
NSObject, the root class of most Objective-C objects in the Cocoa world. This means that by default, all Ruby objects respond to a bunch of handful methods defined in
NSObject, including some that are required by the GC.
Objective-C classes are imported in the Ruby runtime on demand, along with their full hierarchy.
All Ruby objects are actually Objective-C objects. The basic Ruby object structure was modified to conform to the basic Objective-C object structure. This means that Ruby objects can be passed to the Objective-C runtime without any conversion. They will be recognized in the Objective-C world because they have an Objective-C class.
Vice-versa, Objective-C objects can be passed to the Ruby VM without any conversion. They will be recognized as pure Objective-C objects.
The primitive Ruby classes (
Hash) have been re-implemented on top of their Cocoa equivalents (respectively,
As an example,
String is no longer a class, but a pointer (alias) to
NSMutableString. All strings in MacRuby are genuine Cocoa strings and can be passed (without conversion) to underlying C or Objective-C APIs that expect Cocoa strings.
String interface was re-implemented on top of
NSString. This means that you can call any method of
String on any Cocoa string. Because Cocoa strings can be either mutable and immutable, if you try to call a method that is supposed to modify its receiver on an immutable string, a runtime exception will be raised.
NSString was not designed to handle bytestrings, MacRuby will automatically (and silently) create an
NSData object when necessary, attach it to the string object, and proxy the methods to its content. This will typically be used when you read binary data from a file or a network socket.
MacRuby introduces the
Kernel#framework method to require a given C or Objective-C framework into the current runtime.
The method will also locate all the BridgeSupport files in the framework and its dependencies, parse them, and accordingly construct new Ruby APIs. These can be used to access all static APIs, such as C functions, structures, enumerations, constants, and more.
The BridgeSupport parser has been extracted from the RubyCocoa project and rewritten to be language-agnostic. It is very fast, using libxml2's
gperf(1). All symbols retrieved from the BridgeSupport parser are located on demand to avoid unnecessary
MacRuby uses a special syntax to call and define Objective-C methods with keyed/named arguments. It is based on the same syntax that is used to define key/value hash pairs:
:key => value.
MacRuby has a modified version of the parser which detects calls or method definitions using one regular argument, and other arguments using the key/value pair syntax. It will reconstruct the Objective-C full selector if needed. The method name that will be used in the Ruby VM is the same as the Objective-C selector.
The argument order is respected. Multiple arguments with the same name can co-exist, as in Objective-C.
Compatibility is preserved for Ruby-defined methods that expect to receive many key/value pairs, by sending a traditional Hash instead.
MacRuby uses the new Objective-C garbage collector engine, instead of the traditional Ruby GC.
The new collector is generational. It uses write barriers to filter modifications inside the object store to quickly collect generations of young objects. The Ruby runtime was heavily modified to explicitly set the write barriers.
Collections are performed in a separate thread, which doesn't interrupt the program execution flow, except to call finalizers. Fortunately, this happens quite rarely.
ObjectSpace APIs have been re-implemented for the new GC. This has led to, for instance,
ObjectSpace#each_object being available by default, with no runtime cost at all! It even includes all pure Objective-C objects, which is great for debugging purposes.