Bridging the Language Gap

Objective-C, Java, and the Java Bridge

 

Mark Slater

Computer Science Dept., University of California, Santa Cruz, CA 95064

 

Abstract

 

When Apple Computer released MacOS X in early 2001, it included an object-oriented interface to the operating system called Cocoa. Cocoa is unique in that it is available to two different languages, Objective-C and Java. This paper traces the common history of the Objective-C and Java language. It then compares the current state of the two languages. Finally, Apple’s Java Bridge technology, which allows the Cocoa interface to be used by both languages, is examined and explained.

 

1               Introduction

 

In late 1996, Apple Computer purchased NeXT Software in an attempt to invigorate the development of a next generation operating system. Just over four years later, that development effort was realized in the form of MacOS X. The new operating system combines a foundation based on BSD UNIX, and an interface that marries Apple’s original MacOS with the NextStep OS. It also included a development API new to the MacOS development community called Cocoa.

 

Cocoa is based on the original NextStep API, and it is radically different from traditional development APIs on the MacOS and other platforms for two reasons. First, it is a pure Object Oriented API, and second, it has two native languages: Java, and Objective-C. While other platforms have provided Object Oriented APIs in the past (for example, the SmallTalk environment, the Microsoft Foundation Classes, and Java’s Swing), no other major desktop OS provider has ever released an Object Oriented API as its primary interface to the operating system (the MFC is built on top of the standard Win32 API).

 

The languages used to interact with Cocoa are also unique. Java rose to fame almost overnight, and is one of the most popular languages in the world, but its use outside of Sun’s JDK has been limited. Cocoa treats Java as a first-class language, and does not rely on the JDK (though Java code still runs on a Virtual Machine). Objective-C has been around for as long as C++, but did not gain acceptance outside a small community (mostly consisting of NeXT developers).

 

The original NextStep API only used Objective-C; Apple added Java after it purchased NeXT to leverage the vast number of Java developers. In many forums on the Internet, novice developers who have never heard of Objective-C have been wondering why Apple (and NeXT) chose Objective-C and Java as Cocoa’s languages. Many of them see the differences in syntax as a sign that the languages are very different, and miss the language semantics and common ancestry that make Objective-C and Java compatible.

 

1               History

 

For most of the languages in wide use today, the discussion of their history must begin with Algol58 and Algol60.  Algol58 was the first international attempt to create a standard language. The Algol58 report was not intended to specify a formal language, but to stimulate international discussion of language features [16]. It suggested features such as nested selection statements, compound statements, and multidimensional arrays. When the second international committee met to discuss the Algol language, the result was Algol60. The new version introduced scope blocks, stack-dynamic arrays, and two forms of parameter passing: pass-by-value and pass-by-name [16].

 

For Object-Oriented languages, the next important language ancestor is Simula67. Simula67 was based on Simula1 (developed in the mid 1960s); both languages are the product of the Norwegian team Kristen Nygaard and Ole-Johan Dahl. As the language’s name implies, it was developed for the purposes of simulating the real world inside a computer program. The Simula language family was the first to introduce the notion of a class, complete with publicly and privately scoped variables and methods that act on those variables. Another important feature was the construction method that set the class variables to some initial state. Simula67 also introduced the key concept of inheritance, in which a new class is based on an existing one and has access to all its internal state data and methods. In the 1970s, as the idea of data abstraction began to take hold, Simula’s class construct was recognized as the first form this important concept [16].

 

1.1          Smalltalk

 

In 1969, Alan Kay received his Ph.D. from the University of Utah; over the next decade, he revolutionized the computer industry. Alan Kay first spent two years at Stanford’s Artificial Intelligence Lab where he began work on a computer language that would eventually be called Smalltalk. In 1972, Dr. Kay took a position at the relatively new Xerox PARC and began to develop his ideas more fully. Working with Adele Goldberg, with children to test their developments, Dr. Kay spent much of the 1970s working on Smalltalk and many of the technologies we take for granted today (the client-server network model, laser printers, and the Window based user interface) [7]. In 1980, the Smalltalk80 language specification was published. However, it would take many years before the language would see much use. It relied on system support classes that most computers of the time (notably personal computers) did not have the power to support. It was several years after the release of the Macintosh in 1984 (which was inspired by Dr. Kay’s research into windowed user interfaces) before the majority of programmers had easy access to a system capable of supporting Smalltalk.

 

Smalltalk was a radical change from existing programming languages. Most languages of the time used early binding of data structures to their type and hence the functions and operators that acted on them; “early” refers to compile time. Object Oriented languages use a different approach called late, or dynamic, binding (originally seen in Lisp, and then in Simula67). Under this paradigm, the program examines the type of every piece of data at runtime. Each approach has its advantages. Early binding does not need to determine data types since the compiler has already done so; this makes it more efficient and faster. Late binding allows much more flexibility inside the program since the data types can be changed while the program is running.

 

The use of dynamic binding gives rise to another feature of object-oriented languages: polymorphism. Normally, in a language that uses early binding, the compiler creates instructions specific to the data being acted upon (via an operator or function call). Once the program was compiled, the only way to change the function being called was a recompile.  To handle an array of data with varying types, programmers were required to use long CASE statements. Whenever a new type was added, a new handler would have to be written anyplace that type was accessed. With polymorphism, the specific function that is called is not known until the program is running. When the compiler sees a function call, instead of creating a direct call to that function, the compiler generates a call to another portion of the program that examines the data structure and then calls the appropriate function for the data type that is being used. Now, instead of using a large CASE statement, programmers can call methods that are common to all types their code acts upon. When a new type is added, the common methods specific for the new type are also added, but the existing code does not have to change.

 

Although dynamic binding and polymorphism make object-oriented programming possible, the paradigm takes its name from the way in which data is organized in the program. While earlier languages were based on a functional decomposition of a problem, object-oriented programming builds upon Simula’s notion of a class. Programmers build the program from a collection of classes that represent the various real world data types within the program. The relationships between classes usually fall into one of three categories: is-a, has-a, and uses. The is-a relationship is called inheritance, has-a is also known as aggregation, and uses is an association. Inheritance is used when one class (the sub-class) represents the same type as another class (the super-class), with some differences. Generally, the sub-class is either a more specific, or more enhanced version of the super-class. The common example is the super-class Shape, and the sub-classes Polygon and Curve, each of which cold have additional sub-classes. Inheritance can be used to extend a program without changing, or even having access to, the code upon which a sub-class is based. Aggregation is used when one class is an integral part of another; for example, the Room class could be an aggregate of (contain) a Floor class, a Ceiling class, and some Wall classes. An association between classes simply means that one relies on the other for data or functionality. For example, the Hose class has an association with the Water class, but is not a type of water, or made of water. Objects, or variables, are instances of some class. Through the polymorphism mechanism, an object of one type can act as if it is one of the super-class types for that object (for example, a Curve object can be used anywhere that a Shape object is expected), because sub-classes are guaranteed to support all the functionality off their super-classes.

 

Smalltalk is unique, even among object-oriented languages, because it is pure. Most other languages have some imperative constructs, such as non-object primitive types (integer, float, or char), or flow-of-control mechanisms. In Smalltalk, classes represent even primitive types. Flow of control is managed by method calls on various classes. For example, an if() statement in C would be written as

 

if( x > y )

    x = y – 1;

else

    y = x – 1;

 

In Small talk, the expression x > y returns an object of type Boolean. The Boolean class defines the function ifTrue:ifFalse:, which would be used to execute the two clauses:

 

x > y

    ifTrue: [ x := y – 1 ]

    ifFalse: [ y := x – 1 ]

 

Similarly, the Integer class defines a function to:do: which is used in the same way a for() loop would be used in C [15].

 

1.2          C

 

C was developed at the same time as Smalltalk, but with a very different use in mind. C’s development is a direct result of Bell Laboratories’ UNIX operating system. UNIX was developed in the late sixties by Ken Thompson using assembly language. Thompson wrote the first high-level language compiler on UNIX for a language he called B (based on the systems language BCPL). When Dennis Ritchie joined the UNIX project, he created a new language based on B and Algol68. C was designed as a Systems Implementation Language and initially released in 1971. As such, it was a relatively low level language (there was an obvious translation from C code to assembly language), and it was very efficient. Since the UNIX operating system was written in C, the language’s use grew along with the use of UNIX [14]

 

In terms of language design, C did not add anything new. However, its terseness (in terms of source code), and run-time efficiency, coupled with its portability, made it a very popular language. In some ways, C could be considered the culmination of the first twenty years of language design experience. C’s features include a standard library, a large number of operators, and a small number of keywords. There is no concept of late binding in C, all variables are associated with a type at compile time. C does provide the notion of a void pointer, or a pointer to any type. Through this mechanism, a programmer can design a program to act as if it is polymorphic, although the resulting code would be prone to run-time errors, difficult to read, and even harder to debug. C’s greatest legacy may be the languages that were built on top of it.

 

1.3          C++

 

In the early eighties, the theory of object-oriented programming was taking hold in the software engineering community as the solution to the “Software Crisis”. The promise of easily extendable code led to the development of object-oriented compiler extensions for almost every imperative language in use, and the creation of whole new languages. The two most notable extensions (for the purposes of this paper) that arose during this time were C++ and Objective-C (which will be discussed later). Originally called “C with Classes”, Bjarne Stroustrup developed C++ at Bell Labs beginning in 1980. Stroustrup, already familiar with object-oriented concepts though Simula67, designed the language “so that [he] and his friends would not have to program in assembler, C, or various modern high-level languages.” [17] In addition to adding object-oriented features, Bjarne fixed some of the problems he (and others outside of Bell Labs) had with the C language. Many of these fixes were incorporated back into C when it was standardized in 1989 [16]

 

As with C, one of the primary considerations in the design of C++ was efficiency. One of the first uses of the new language was for “event-driven simulations for which Simula67 would have been ideal, except for efficiency considerations.” [17] The other goals were incorporating object-oriented features into an accepted development language that could be used as a System Implementation Language, as well as general-purpose programming [14].

 

C++ combines features seen in many languages that preceded it. It has all the features of C, including early binding (the default), a standard library (aside from the STL), aggregate data types (the C struct), and the standard imperative language flow of control constructs. In addition, C++ provides for dynamic binding of functions (through the use of the virtual keyword), data and function access modifiers (public, private, and protected), the object-oriented class construct, inheritance, function and operator overloading, and reference types [6].

 

The first implementation of C++ was released in 1985 in the form of a program called Cfront. Cfront translated C++ code into C code that could then be compiled by a standard C compiler. It has gone through many releases since that time, and in the late nineties, was made an ANSI and ISO standard. Some of the features C++ gained in that times include multiple inheritance, templates for generic programming (along with a Standard Template Library, or STL), exception handling, and language support for abstract classes [16].

 

2               Objective-C

 

At the same time Bjarne Stroustrup was developing C++, another researcher named Brad Cox began a project with a similar goal: “C was grand for fabricating stuff but weak at assembling prefab components. [Objective-C was built] as a soldering gun for C as the silicon fab line.” [4] While Stroustrup decided to fix and redefine some of the C language, Cox made only additions to the C language; nothing that existed in C was changed in creating Objective-C. The effect is that C++ creates “a better C” [12] and a larger, more complex language, while Objective-C created a better vehicle for the object-oriented constructs of encapsulation, inheritance, and polymorphism. The difference in the complexity of the final languages can be seen in the standard language guides – “The C++ Programming Language, 3rd Edition” by Bjarne Stroustrup is over 900 pages, while “Object-Oriented Programming and the Objective-C Language” by Apple Computer is about 200 pages (including the formal language grammar for the Objective-C extensions).

 

2.1          Object-Oriented Features

 

A major difference between Objective-C and C++ is the language used as the basis of the object-oriented features. Where C++ was based on Simula67, Objective-C is based on Smalltalk80. This difference alone leads to very different languages. While Simula67, as noted earlier, was the basis for the object-oriented paradigm, Smalltalk80 was the culmination of a decade of development, and was the first pure object-oriented language. The syntax of Objective-C’s extensions are taken from the Smalltalk80 language. For example, in a Point class might be defined as follows:

 

C++

Objective-C

class Point

{

public:

    Point(); // constructor

   

    // Polymorphic function declaration.

    virtual set (int newX, int newY);

   

    // Non-polymorphic functions.

    int getX();

    int getY();

 

protected:

    int x;

    int y;

}

@interface Point : NSObject

{

@protected

    int x;

    int y;

}

 

/* Allocation – A Class function */

+ (id) alloc;

 

/* Construction – An instance function */

- (id) init;

 

/* Messages – Instance functions */

- (void) setX: (int) newX Y: (int) newY;

- (int) getX;

- (int) getY:

 

 

C++ uses dynamic binding on pointers and references to objects, and static binding on stack objects. In addition, class methods are not polymorphic by default; the virtual keyword is required in the function prototype. On the other hand, Objective-C uses static binding for variables declared as pointers to an object and dynamic binding for generic objects. The type of a generic object is id, and the Objective-C compiler allows any message to be sent to a variable of this type, assuming the object it represents at run time will respond to the message; in fact, the compiler only ensures that variables of type id are only used with object types. Even if a variable is statically typed in the source code, messages to the object are still handled dynamically at run time [1]. To continue the Point class example, variables of type Point would be used like this:

 

C++

Objective-C

{

    // A statically typed variable.

    Point staticPoint;

   

    // A dynamically typed variable.

    Point *dynamicPoint = new Point();

   

    // Never a polymorphic call.

    staticPoint.set( 5, 5 );

    

    // Eligible for polymorphic behavior.

    dynamicPoint->set( 5, 5 );

}

{

    // A dynamically typed object.

    id obj = [ [ Point alloc ] init ];

 

    // A statically typed object.

    Point *pt = [ [ Point alloc ] init ];

 

    // Polymorphic messages

    [ obj setX: 5 Y: 5 ];

    [ pt setX: 5 Y: 5 ];

}

 

In C++, if a subclass of Point were defined (say Point3D), the variable dynamicPoint would be able to point to an object of type Point or Point3D, whereas the variable staticPoint can only point to an object of type Point. In the Objective-C example, the compiler will generate a warning if the variable pt is set to refer to an object that is not of type Point, or a subclass of type Point. But at run time, both variables are allocated dynamically.

 

2.2          Basic types: NSObject and Class.

 

Another feature Objective-C borrowed from Smalltalk is the use of an extensive standard library of pre-built classes. At the top of the class hierarchy is the NSObject class; if a new class has no other superclass, it must inherit from NSObject. The NSObject class provides access the run time type information about an object, as well as allocation and deallocation (the current Apple implementation of Objective-C supports reference counted garbage collection for deallocation; the original language design had support for garbage collection but did not actually implement it). Also included in the NSObject class are messages for testing equality, computing a hash code, and getting a description of the object in the form of an NSString. The NSObject class should not be confused with the id type. id is similar to the semantics of the void * in C, while NSObject is a specific class.

 

During compilation, the Objective-C compiler gathers data from the various source files for each class and puts that information into an object of type Class. The Class object also contains the class messages, including construction messages. As seen in the above example, to create a new object, an alloc message is sent to the class object for the needed type. One of the benefits of Objective-C is that the Class object that is sent the message can be a variable; this allows the program to decide at runtime what type of object is allocated.

 

2.3          Extending a class: Categories and Protocols

 

One of the most innovative features of Objective-C is called a Category. Categories allow an existing class to be augmented with new messages. The normal object-oriented approach to adding features to a class is inheritance. Categories allow features to be added to an existing class so that all variables of that type have access to the new messages, not just subtypes. Categories can only define new messages, they cannot add instance variables; however, a Category has access to all instance variables within the original class, including the private ones. An example of where this is useful is the NSString class. NSString declares many messages that allow conversion to numeric types, but does not provide conversion of Boolean types. Rather than creating a new subclass of NSString, a Category that adds the messages needed for the new functionality can be created. Note that the semantics of the class are not changed by the addition of the Category; subclasses are expected to be semantically different from their superclass, but Categories are not (though there is no language feature to prevent this) [1]. Here is the source code for creating the BoolConversion Category of NSString:

 


@interface NSString( BoolConversion )

 

+ (id) stringWithBool: (BOOL) value;

- (BOOL) boolValue;

 

@end

 

Objective-C, like Smalltalk, does not support multiple inheritance. However, it does recognize that some objects not semantically related to each other (in the class hierarchy) may have a set of messages in common. To formalize these common message sets, Objective-C uses a construct called a Protocol. Protocols are similar to pure abstract classes in C++, except that they are not allowed to declare instance variables. Classes can conform to as many Protocols as they desire, even though they can only inherit from one class. Also, variables can be typed as protocols, and any class that implements the Protocol type may be assigned to that variable. Objective-C supports two levels of Protocols: formal and informal. Informal protocols are implemented as Categories of NSObject. This allows any object in the class hierarchy to implement the messages declared in the Category. The tradeoff is that there is no language support for informal protocols, since there is no implementation that accompanies them; the compiler is unable to provide type checking, and the run time system is unable to ensure an object conforms to a specified protocol. Formal protocols, on the other hand, have full language support and can be checked by both the compiler and run time system. Formal protocols can be declared for Classes or Categories [1]. The following example defines a Protocol called Drawable and shows how the earlier example of a Class and Category would signify they conform to the Protocol (the actual implementation is not shown, but it would look the same as any normal Class message implementation).

 

@protocol Drawable

- (void) draw;

@end

 

@interface Point : NSObject <Drawable>

@interface NSString( BoolConversion ) <Drawable>

 

Protocols also include syntax to support distributed object communication, but this feature is not discussed in this paper.

 

2.4          The Run Time System

 

The other major language feature that Objective-C borrows from Smalltalk is the run time system. Smalltalk was originally implemented as an interpreted language, and therefore relied on a virtual operating system supplied by the interpreter (this is one of the reasons Smalltalk has never been known for run time efficiency). An instance of the Objective-C run time system runs beneath each application built with the language (they are never shared) to support the dynamic nature of the language. When a message is passed to an object, the run time system handles the mechanics of calling the correct function code by checking the type of the object that is to receive the message and making sure objects of that type can respond to the message. Many of the messages in the NSObject class interact directly with the run time system, most notably the messages involved in run time type access.

 

C++ uses the keyword new to allocate memory and a special constructor method defined by the class to initialize a new object. Objective-C also uses a two-step process to prepare objects for use. But instead of a new allocation keyword, Objective-C defines a function in the NSObject class called alloc that uses the run time system to allocate memory for the new object. To initialize a newly allocated object, each class is expected to respond to the init message. The compiler does not enforce the existence of init. Likewise a class can define several initialization messages (convention dictates the name of each of these messages begins with init, and that a comment or library documentation specifies the “designated initializer” for the class).

 

Although the run time system could have been built with full garbage collection support, the current Apple implementation does not do so. Instead, each object is reference counted with support built into NSObject. When an object’s reference count reaches zero, a dealloc message is sent to that object. The dealloc message defined in NSObject simply uses the run time system to release the memory occupied by the object. All classes are expected to override dealloc to decrement the reference count of any object they hold and release (using the standard C library function free()) any memory allocated directly by the object, before sending a dealloc message to their superclass.

 

The other important feature supported by the run time system is message forwarding. If an object does not respond to a message directly, the run time system sends it a forwardInvocation message (defined by NSObject) along with an NSInvocation object containing the original message and its arguments. Message forwarding is another way to implement aggregation in Objective-C. Rather than redefining an interface that is internally handled by an aggregate object, and manually forwarding each message, the following code can be used to forward all messages supported by the aggregate (extra code would be needed to limit the messages forwarded to the object if the complete interface is not desired).

 

- (void) forwardInvocation: (NSInvocation *) anInvocation

{

    if( [ aggregateObject respondsToSelector: [ anInvocation selector ] ] )

    {

        [ anInvocation invokeWithTarget: aggregateObject ];

    }

    else

    {

        [ super forwardInvocation: anInvocation ];

    }

}

 

(This example was taken from Apple documentation [1]).

 

3               Java

 

In 1990, Patrick Naughton, Mike Sheridan and James Gosling began working on a Sun project known as Green, “chartered to spend time (and money!) trying to figure out what would be the "next wave" of computing and how [Sun] might catch it” [9]. The Green project, when it was finished in 1992 had two major results: a PDA based on Sun’s SPARC processor technology, and the Oak programming language. Of the two, Oak turned out to be the more important. It was renamed Java and has become one of the most popular programming languages in the world.

 

One of the things developers of a new language are generally concerned with is reducing complexity; usually the complexity of a problem domain. Java, on the other hand, “seems [to have the] unflinching goal of reducing complexity for the programmer.” [5] While that may have been the result, the stated goals of the Java language development were a language that:

[10].

 

Although the first version of Java was finished in 1992, the world did not hear about it until 1995, when Sun released the HotJava browser, capable of displaying web pages containing mini-applications called Java Applets.

 

3.1          Similarities to Objective-C

 

There is more than a common heritage behind the similarity of Java and Objective-C. Patrick Naughton was on the verge of leaving Sun for a job at NeXT when Sun’s CEO, Scott McNealy (who was on his intramural hockey team) convinced him to stay for the Green project. Naughton writes:

 

When I left Sun to go to NeXT, I thought Objective-C was the coolest thing since sliced bread, and I hated C++. So, naturally when I stayed to start the (eventually) Java project, Obj-C had a big influence. James Gosling, being much older than I was, he had lots of experience with Smalltalk and Simula67, which we also borrowed from liberally.

 

The other influence was that we had lots of friends working at NeXT at the time, whose faith in the black cube was flagging. [Many of them] joined us in late ’92 - early ’93 after we had written the first version of Oak.  I’m pretty sure that Java's ‘Interface’ is a direct rip-off of Obj-C’s ‘Protocol’ that was largely designed by these ex-NeXT’ers... Many of those strange primitive wrapper classes, like Integer and Number came from Lee Boynton, one of the early NeXT Obj-C class library guys who hated ‘int’ and ‘float’ types. [13]

 

Beyond that, Java has support run time type access through its’ Reflection API. The Java language also keeps data about the classes in the application in a Class object that can be queried at run-time. Java also requires a support system at run-time to handle object allocation, deallocation, and method calls; but Java’s virtual machine was designed to meet additional needs that Objective-C does not have (see the next section).

 

Java’s class hierarchy also has similarities with Objective-C. Both hierarchies all inherit from a single class, and only single inheritance is supported. As Patrick Naughton wrote, Java has an equivalent of Objective-C’s Protocol construct called an Interface. Java also comes with a large library of classes to handle common programming tasks (for example, collections of data, terminal IO, string handling, file access, and network access).

 

3.2          Differences from Objective-C

 

When looking at Objective-C code, side-by-side with Java code, the first thing that most people would notice is the difference in syntax. Java chose to use C++ syntax as its basis, and build from there. This decision was made for a few reasons: the designers were all comfortable with C++ syntax (even if it wasn’t their favorite language), the similarity could be used to “seduce” programmers into trying Java, they didn’t want to disrupt too many “entrenched attitudes”, and in the end it was “as good as any other” [10].

 

Beyond the simple difference in syntax, Java’s compiler does not turn Java code into machine code. Instead, it produces a platform independent object file that contains ByteCode. When a Java program is run, the virtual machine interprets the ByteCode (although today, Just-In-Time compiler technology is being used to compile the ByteCode to machine code on the fly). The ByteCode serves two major purposes. First, it gives the language a more efficient representation than source code, while still retaining platform independence. And second, it makes it easier for the virtual machine to perform run time analysis of the code is it about to execute.

 

While the mere existence of Objective-C’s run time system and Java’s virtual machine speak of a common heritage (Smalltalk80), the implementation of the two systems is very different. One of the most noticeable differences between Objective-C’s run time system and Java’s Virtual Machine is the built in garbage collection. This allowed the Java team to remove programmer specified pointer variables (making Java easier to secure), and makes programmers more efficient (a great deal of time is spent trying to find memory leaks in programs that do not use garbage collection, to the point where there are many programs written specifically to assist in this task). The Java Virtual Machine also does more run time type checking than Objective-C, using a built in Security class hierarchy to examine code before it is executed and ensure it will not perform a forbidden task (like formatting the hard drive of the user’s computer). The Virtual Machine also allows Java code to be more portable than Objective-C, which still has to deal with C portability issues on various platforms (for example, little-endian versus big-endian).

 

Exception handling is given a high priority in the Java language. The language syntax supports exception handling in the style of C++, but unlike C++, the compiler enforces catching for most exceptions; those derived from the RuntimeException class do not have to be caught because they generally arise from problems in the virtual machine (divide by zero, security violations, ByteCode incompatibilities, and invalid states). The benefits of exception handling include increased security, and the ability to enforce an interface. It also allows program designers the ability to recover from problems (unlike C’s assert library which can only stop program execution).

 

Java also provides language support for threading, and makes use of that support within its Swing user interface library. Any program that accesses almost any part of the Swing library will cause Swing to start a separate thread to monitor user events. The virtual machine handles threads by default, but on machines with multiple processors, the thread support can be delegated to the operating system for even better performance and true multitasking.

 

Other language differences are smaller (though not less significant). Java has a stronger type system than Objective-C. This is both a security decision and an efficiency concern. While Objective-C includes a generic object pointer (the id type), Java’s most generic type is java.lang.Object (the equivalent of the NSObject class), and the Java compiler does not automatically cast objects. Java’s encapsulation mechanism supports the methods as well as data to be scoped for privacy. Early binding in Java can be specified with the final keyword that also prevents a function or variable from being overridden in subclasses. Java does not have constructs equivalent to Objective-C’s Category, or message forwarding.

 

4               The Java Bridge

 

Java’s designers understood that most programmers coming from the languages of C and C++ would have two major concerns they did not necessarily share: run time efficiency and access to legacy code. The first version of Java included language support for “native methods” defined with the native keyword. As Java’s usage grew, the native language support grew into the Java Native Interface (JNI). The purpose of the JNI is to allow Java code running on the virtual machine to access libraries written in other languages (presumably ones that are compiled into the “native” machine code for a specific platform).

 

One of the most popular uses of the JNI has been to connect an existing backend written in C or C++ with a Java AWT or Swing user interface. Another common use is to provide fast execution of some portions of a program that can take advantages of special hardware or operating system features not available through the virtual machine.

 

One of the more exotic uses of the JNI is Apple’s Java Bridge. In the development of MacOS X, and the repackaging of the NextStep API as Cocoa, Apple decided to add direct support for the Java language. Realizing that there are far more Java programmers than Objective-C programmers, Apple is hopping the availability of a direct API to the operating system will win more developers to the platform and allow existing Macintosh developers (all of whom are new to Cocoa and Objective-C) to begin developing new applications without having to learn the idiosyncrasies of a new language as well as a new interface. To facilitate this development, they created a technology that relies heavily on the JNI.

 

Once the proper setup has been done, you can:

·      Instantiate and use classes from one language in the other.

·      Pass objects as arguments and receive objects as return values from one language to the other.

·      Directly subclass Objective-C classes in Java.

·      See Objective-C protocols as Java interfaces.

[2]

 

For the Cocoa API, Apple simply created Objective-C classes that were wrapped with an extra specification file (called a “Java to Objective-C Bridging Specification”, or .jobs, file) and a JNI based library to handle the translation between the two languages. Once a class is written in either language, a utility program called bridget can be used to generate the needed stub code for the other language (alternatively, the stub code can be written by hand).

 

Some of the classes in the Cocoa API have direct mappings in the Java API. The Java Bridge handles these classes differently (most classes are simply handled by a proxy object the bridge creates to handle communication). For classes such as NSString, NSNumber, and NSException, programmers do not have to do any extra work; the Java Bridge simply “morphs” them to their corresponding classes – java.lang.String, java.lang.Number, and java.lang.Exception.

 

Morphing NSException to a java.lang.Exception (and vice versa) has an interesting side effect. Objective-C’s support for exceptions is not built into the language, while in Java, exceptions are a part of a method’s definition, and the compiler forces the programmer to handle all possible exceptions. Because of this, Objective-C exceptions, when thrown to Java code, must be handled, while Java exceptions, when thrown to Objective-C code, do not have to be handled. In the latter case, the Java Bridge catches the exception (satisfying the Java language requirement) and then throws an equivalent Objective-C exception [2].

 

To use Java classes within Objective-C, the Java Bridge provides the NSClassFromString() function. This function returns an Objective-C Class object that can then be sent an alloc message to create a new instance of the object. If a .jobs file exists for the class that has been instantiated, the function names are mapped as described there. Otherwise, the Java Bridge “automatically derives the Java method name from the Objective-C selector name by removing everything beyond the first colon. Thus, a method such as sendBar: x foo: y would map to sendBar( x, y )“[2].

 

When using an Objective-C class from Java, there is more work to be done. Since Objective-C is not strongly typed, as Java is, a .jobs file is required to provide the Java compiler with the information about the class that it needs. Another problem is arises from differing language syntax.

 

Objective-C methods use keywords for method arguments, while Java uses comma-separated lists (as with C and C++). For example, in Objective-C, the following declares an instance method that takes two parameters:

 

-(void) setObject: (id) anObject forKey: (id) aKey;

 

In Java, the same method is declared as follows:

 

void setObjectForKey( Object anObject, Object aKey );

 

[2]

 

This difference in syntax, and the automatic function generation provided by the Java Bridge sometimes causes two messages in Objective-C to map to the same Java method name; these cases must be explicitly handled by the .jobs file, or the program may suffer from run time errors. The only major restriction on wrapped Objective-C classes is that their instance variables are not directly available in Java, even for their subclasses. Apple’s Project Builder provides a standard project template for wrapping Objective-C classes to be used with Java.

 

Categories also provide a unique challenge. Since there is no Java construct for them to map to, the Java Bridge has no default method of handling them. It is left to the developer providing a specific mapping between the two classes to deal with. Apple’s Cocoa API generally adds the Category functionality to the class it were designed to augment, but sometimes creates new base classes [11]. For developers using Categories to add functionality to a library that already has a Java equivalent (Apple’s Cocoa APIs for example), this will create a problem that Apple’s documentation does not address. One way around this problem might be to create an Objective-C subclass that represents the library class with the category, and then use the Java Bridge to wrap the subclass for use in the Java code, but this approach has not been tested.

 

The other difference that can cause problems in bridged code is the use of pointers in Objective-C code. It is common in Objective-C (and other languages derived from C) to pass multiple pointers to variables as function arguments (pass-by-reference), allowing the function to return multiple values. Since Java objects are always treated as pointers to objects, the Java Bridge is able to handle pointers to Objective-C objects with no problems. However, some Objective-C functions may require pointers to primitive types. In this case there is no Java equivalent, and the function would have to be split, with each new function returning a single value. Another option is to create an Objective-C struct to contain all the data returned, but this would require additional wrapping of the new struct. But the best way of handling this situation may be to use an NSDictionary (which Apple provides morphing support for) to combine all the values into a single object that is then returned by the function.

 

4.1          Objective-C++

 

Since Objective-C and C++ essentially share the same imperative syntax of the original C language, it is a simple, if tedious, task to write code that bridges the two languages; the extern “C” { … } construct is well known to C++ developers who need to interface with existing C code.  According to posts on various newsgroups and message boards over the past year, Apple is working on Objective-C++, and has had some success in merging the code with the current gcc compiler. Brad Cox “was pushing Objective-C++ from the day C++ came out. Unfortunately by then [the language] picked up [its] own load of bigots to which the very idea was anathema.” [4] It remains to be seen, whether or not Apple will continue this work and release it, but it would ease the process for so many of their key developers, it is hard to imagine Objective-C++ being put on a shelf for very long.

 

Efficiency problems with Java create another case for Objective-C++. Although the Java Bridge itself is very efficient, the Java code is still running on a virtual machine. While current Java programs can sometimes approach C++ in terms of execution speed, the multimedia applications for which the Macintosh platform is known require every bit of processing power the computer can provide. Even though Objective-C will run faster than Java (simply because it doesn’t run on a purely virtual machine), equivalent C++ code is generally faster.

 

5               Conclusion

 

The common history of Objective-C and Java has produced languages that, while very different on the surface, are almost identical underneath. They are both highly dynamic, and come with excellent class libraries to handle basic tasks that all applications need. Both languages are still being developed in one form or another, and both are taking on features found in C++ (generics are being added to Java in its next major release).

 

When Apple Computer began development of MacOS X, its primary goal was to provide a modern operating system for its users. During the development of the Cocoa API, they became aware that Java, and the Java Native Interface, provided a unique opportunity to leverage the existing Objective-C classes and create an efficient map between the two languages. This has the dual benefit of shortening the learning curve for developers who already know Java, and allowing existing Java code to be easily ported to the new operating system.

 

Apple’s Java Bridge is not the only such technology. The open source GNUstep project, which is trying to create an API for XWindows that is compatible with Cocoa at the source code level, has created an automated bridge library called “Java Interface for GNUstep”, or JIGS [8]. There are many developers (MacOS and others) watching the GNUstep project’s progress, hoping that eventually it will provide access to the complete Cocoa API on Windows as well as UNIX. This would benefit developers for all three platforms – for the first time, there would be a single object-oriented API that provides access to the three most popular operating systems. The addition of Java Bridging technology makes communication between the platforms simple; objects passed through the Java Bridge will always come out in the format appropriate for the receiving system.

 

 

References

 

[1]    Apple Computer. “Object-Oriented Programming and the Objective-C Language.” WWW publication. 2000. (published at http://developer.apple.com/techpubs/macosx/Cocoa/

ObjectiveC/ObjC.pdf)

 

[2]    Apple Computer. “Using the Java Bridge.” WWW publication. 2001. (published at http://developer.apple.com/techpubs/macosx/Cocoa/ProgrammingTopics/JavaBridge/

JavaBridge.pdf)

 

[3]    Cox, B, and Novobilski, A. “Object-Oriented Programming: An Evolutionary Approach, Second Edition.” Addison-Wesley Publishing Company. Reading, Massachusetts. 1991.

 

[4]    Cox, B. personal communication. 2001.

 

[5]    Eckel, B. “Thinking In Java, Second Edition.” Prentice Hall, Upper Saddle River, NJ. 2000.

 

[6]    Eckel, B. “Thinking In C++, Second Edition, Volume 1.” Prentice Hall, Upper Saddle River, New Jersey. 2000

 

[7]    Gasch, S. “The History of Computing: Alan Kay”. Virginia Tech, Department of Computer Science. http://ei.cs.vt.edu/~history/GASCH.KAY.HTML

 

[8]    GNUstep. www.gnustep.org.

 

[9]    Gosling, J. “A Brief History of the Green Project.” Sun Microsystems. http://java.sun.com/

people/jag/green/index.html

 

[10]  Gosling, J. “The Story of Java.” The Computer Museum. 2001. (published at http://java.sun.com/people/jag/Presentations/TheStoryOfJava/img0.htm).

 

[11]  MacOS X. Release Notes. Apple Computer. 2001

 

[12]  McHale, W. “Object-Oriented C – A Case Study of C++ and Objective-C as Object-Oriented Extensions of C.” University of Maryland: Baltimore County. http://userpages.umbc.edu/~schmitt/331S96/wmchal1/testdraft.html.

 

[13]  Naughton, P. comp.sys.newton. (published at http://virtualschool.edu/lang/objectivec/

influenceOnJava.html).

 

[14]  Pohl, I. Class lectures – “Programming Languages”, University of California: Santa Cruz. Spring Quarter, 2001.

 

[15]  Savic, D. “Object Oriented Programming With Smalltalk/V”. Ellis Horwood. London. 1990.

 

[16]  Sebesta, R. “Concepts of Programming Languages, Fourth Edition.” Addison Wesley Longman. Reading, Massachusetts. 1999.

 

[17]  Stroustrup, B. “The C++ Programming Language, Second Edition.” Addison-Wesley Publishing Company. Reading, Massachusetts. 1991.