Bridging the Gap Between Java and Cocoa

Many Java developers are looking at new dynamic languages, such as Groovy and JRuby, mostly because of the freedom and rapid development that a dynamic language allows. Some of my colleagues are also looking at Cocoa and feel daunted at the sight of Objective-C.

Here I will use a small example that is easy and natural for Ruby, but equally hard for Java and Obj-C. That way both languages stand on equal grounds for comparison.

This article explains the Objective-C parts in detail, and Java in brief. It is assumed that you as a reader understands Java well. Many concept in Java and Obj-C are identical, but with different names. I will be using the Java names in Java context, and the Obj-C names in Obj-C context. Therefore; memorize this short glossary:

Cocoa relies heavily on features in the Obj-C langauges, so even if Cocoa apps can be written, and is so supported by Apple, in Ruby or Python; Obj-C is the only language that can tap into the full power of Cocoa.

Cocoa on Mac OS X is an umbrella framework for Foundation and AppKit. Cocoa Touch on iPhone OS is an umbrella framework for Foundation and UIKit. This post only uses features from the shared Foundation framework, and this is applicable for both Mac OS X and iPhone OS.

The Ruby Problem

Ruby makes it extremely easy to work with arrays. For the sake of this post I want to convert an array of numbers into an array of strings. Performing the same operation on an arbitrary list of objects, and then resturn a list with the results.

First line sets up an array of numbers, and the second line creates a new array by executing a block against each element, and then we print it out. The block can be seen as a closure, Java nor Obj-C have closures, at least not yet. Objective-C 2.1 will be public this summer and introduce blocks, that can be seen as closures.

With no closures at hand today, both Java and Obj-C will have to solve the problem by executing a method on each element. In this example toString() in Java and the Cocoa equivalent description.

Java Implementation

For the Java implementation we need to introduce a utility class. This utility class I call ListCollector, and it uses generics to allow for different kinds of inputs and results. This utility class could be implemented like this:

Our utility function collect takes two arguments; a List with elements, and a Collector implementation to invoke on each element. This do not use a closure as in the Ruby example.

A simple example of how to use this utility in the same veine as in the previous Ruby example:

Cocoa Interaface

In Cocoa you never have utility classes, instead you use categories to add new functions to already existing classes. A category can be seen as a mix-ins, it allows us to add and replace class and instance methods, as well as protocol conformance on already existing classes.

That is the good stuff, the bad stuff is that Obj-C do not know of final. So if an implementation is brittle, the only safety against bad programmers is the documentation you write. In fact Obj-C do not know of visibility, all methods are public. You can only hide a method by not displaying it in the public interface of your classes (your users may still guess at the names and use it anyway).

That leads us to interfaces, Obj-C just as C and C++ uses interface files; .h files. So lets define our category:

First thing we note here is that the method name is quite long; resultsFromMakingObjectsPerformSelector:withObject:, and that arguments are interleaved. At first glance it might look like named arguments, this is an illusion, they are merely interleaved with the : character. Looks strange, but the result is surprisingly readable and self describing code.

Note that is do not use a closure as in Ruby, nor an inner class as in Java, but a reference to a method identifier in the form of the SEL argument.

Cocoa Implementation

Just as C and C++ has interface files, so do Obj-C have implementation files; .m files, or .mm for Objective-C++ where you can mix C++ with Objective-C.

The implementation is quite familiar:

First we create a NSMutableArray, in Cocoa there are two classes for arrays; NSArray that is immutable, and the subclass NSMutableArray that is mutable. Then we use the for each statement to iterate over our input array. Then comes the first real difference from Java, and a clear display of the dynamic nature. Obj-C, nor Cocoa have support for generics. The use of the generic id object type avoids the need for most typecast, but you should be aware that they implicitly are there.

Methods are first class citizens in Obj-C, not tucked away in a utility package. A method in Obj-C consists of two parts; the selector and the implementation. The selector has the type SEL, and the implementation is IMP. Both can be passed around just as any other primitive type or object instance.

The selector is the identification of the method, think of it as the name. The selector is shared for all classes implementing a method with the same signature. If one class implements someMethod: and another class, in a completely other even dynamically loaded framework, also implements someMethod: both are guaranteed to be equal. The root object NSObject in Cocoa implements methods for dynamically invocing methods baseds on selectors, one of them is the one used in the code above performSelector:withObject:.

The implementation of a method is a function pointer to the actual executable code that implements the method. It can be shared between classes, as is often the case for subclasses. But can also be freely passes around, and exchanged for some quite powerful and useful tricks.

Cocoa Use-case Example

Obj-C is a strict superset of C, so just as you have a main function in C, so do Obj-C. For most Cocoa application you never need to worry about this, the template from Xcode will generate the main function and all you see is OOP goodnes. For this small example I will do the test code in a main function of my own. If you cut and paste code from this example, be sure to create a project from the “Command Line Utility”->”Foundation Tool” template in Xcode.

The NSAutoreleasePool is part of Cocoa, and is used to seemingly garbage collected framework. Cocoa for Mac OS X can be garbage collected, Cocoa Touch for iPhone OS is not garbage collected.

The second statement created an array instance with three NSNumber objects. NSNumber is equivalent to java.lang.Number and all of it’s subclasses, Cocoa do not have a separate subclass of NSNumber for each primitive type. NSNumber is a subclass of NSValue, that can hold any C type value including structs and unions.

The third statement is where we call the method we defined and implemented above. Note how we call this on a stock Cocoa class, not on a utility class. We use the @selector() compiler directive to retrieve a selector of SEL type from a human readable name, and pass nil the Objective-C equivalent of null as argument.

Lastly we send the result converted to a string to NSLog() function. NSLog() is a C macro with printf syntax that is used to send text to standard out. NSLog() can be removed from release builds.

Last Words

It is important to understand the concept of selectors, and how passing around SEL arguments works. In Java libraries callbacks are often handles using listener interfaces, where the listener implements an interface and a specific method is called. In Cocoa listeners are implemented using the target-action paradigm, where the intended listener is passed along with the SEL specifying which method to send the callback to.

As an example when setting up the event listener for user tapping a control in Cocoa Touch on iPhone OS:

What this means is that the need for anonymous inner classes is removed, and the same class can in a natural way receive the same event from different senders.

For more complex, or grouped event handling protocols are used. The classes conforming to the listeners protocols are not referred to as listener, but as delegates, yet again different name but same concept. But even now the dynamic language come into play, as a class is not required to implement all methods from a protocol in order to conform to it (Think of it as if some methods in a Java interface could be optional, and then are treaded as no-ops).

A protocol in Obj-C can have optional methods. Implementor of the NSTableViewDataSource protocol may for example choose to implement, or not to implement the method tableView:setObjectValue:forTableColumn:row:. If not implemented the table is read-only, by implementing this single method the table is editable and functionality such as pasting into the cells is provided for free.

It is very important for developers new to Cocoa and Obj-C to grasp the concepts of target-action, and delegates. This is the core principles that drive the application frameworks for Mac OS X and iPhone OS.

4 Comments

  1. Small typo in the “The Ruby Problem” section: “and then resturn a list”, should be “return” =)

  2. jakob

    Maybe instead of introducing a hand-written ListCollector, use apache’s CollectionUtils:

    public class ListExample {
    public static void main(String[] args) {
    Collection list = Arrays.asList(new Number[]{12, 42, 366});
    Collection results = CollectionUtils.collect(list, new Transformer() {
    public Object transform(Object input) {
    return ((Number)input).toString();
    }
    });
    System.out.println(results);
    }
    }

    Granted, they still don’t use Generics, but otherwise it’s more java-like to pass a anonymous interface-implementation as a quasi-closure.

  3. @jacob: Yes for real implementations that is what I would do. For the sake of this example I wanted to execute any method without the need for an abstract glue instance.

    But your point is taken, I should update the Java-example to be “what Java coders expect”.

  4. Ben S

    Interesting article. Thanks!

Leave a Reply