News: Stay up to date

The Étoilé community is an active group of developers, designers, testers and users. New work is being done every day. Visit often to find out what we've been up to.

News

Prototypes (Again!)

Posted on 8 August 2011 by David Chisnall

In 2007, while sitting in the lobby of Google Zurich, I wrote an implementation of prototypes and traits / mixins in Objective-C. Since then, Quentin has largely rewritten the traits support (see the last blog entry). I rewrote the prototypes support once to better support the new runtime - using runtime functions rather than manipulating the runtime data structures directly.

When I added support for associative references to the new runtime, I borrowed a lot of the code from the old prototypes implementation. The objc_setAssociatedObject() and objc_getAssociatedObject() runtime functions are effectively implementing the ability to store objects in slots, as with JavaScript objects.

There are a few other things required to completely implement the JavaScript object model in Objective-C:

  • The ability to add methods to a single object, not just store values. This isn't strictly required, because JavaScript doesn't really have methods. Slots just return closures, which you then call.
  • The ability to clone an object, so that slot lookups (including methods) are satisfied by the prototype if they can't be satisfied by the object.

These are now both supported in the GNUstep runtime, and will be part of the 1.6 release. We now have an object_addMethod_np() function, which is the counterpart of class_addMethod(). The arguments are almost identical, but it takes a single object instead of the class and just modifies that object.

We also have object_clone_np() and object_getPrototype_np(). These clone an object and return its prototype. The prototypes support in EtoileFoundation is now just a thin wrapper around these.

Because this stuff works in Objective-C, we can also use it in languages that LanguageKit supports. For example, you can run this little Smalltalk program:

NSObject subclass: SmalltalkTool
[
    run
    [ |a b |
        a := NSObject new.
        b := a clone.
        a setValue: [ :this |
            ETTranscript show: 'self: ';
                         show: this;
                         show: ' prototype: ';
                         show: this prototype;
                         show: ' foo: ';
                         show: (this slotValueForKey: 'Foo');
                         cr ]
           forKey: 'print'.
        a print.
        b print.
        b setValue: 'A fish!' forKey: 'Foo'.
        b print.
    ]
]

The output is:

self: <NSObject: 0x2b3b081c> prototype: (null) foo: (null)
self: <NSObject: 0x2b2d9efc> prototype: <NSObject: 0x2b3b081c> foo: (null)
self: <NSObject: 0x2b2d9efc> prototype: <NSObject: 0x2b3b081c> foo: A fish!

If you've been following LanguageKit development, then you may have noticed that there is a front end for a language called EScript. This is a toy language that is intended to demonstrate that it's possible to implement JavaScript-like languages using LanguageKit. There's a simple test program in svn that shows some of this working. Note the JavaScript-like control structure, and the ability to create new objects by cloning existing Objective-C (or Smalltalk) objects.

As always, this is lowered to the same sort of code that you'll get from Objective-C. Prototypes are generally slower than classes in the current implementation, but they are more flexible, and the advantage of LanguageKit is that you can combine the two easily. A language like EScript would be great for prototyping, while a language like Smalltalk is better for the real implementation. In the future, we'll be able to move between them completely fluidly.

Oh, and while I'm talking about EScript, the current code in svn is the result of a big refactoring effort. I've cleaned it up in a lot of places, and it now uses ARC or GC, not its own ad-hoc retain / release code. This should make it a bit more reliable, and means that it can benefit from the same ARC optimiser that clang uses. Expect a new release soon...