Editor's note: Recently James Duncan Davidson published a series of weblogs on the subject of Java and Mac OS X for O'Reilly Network. These blogs contained lots of useful information that was too good to get buried deep within the network labyrinth, so we've updated them and are now presenting the content in a series of three articles. This is part three of this three-part series.
Today Davidson takes a look at Cocoa, and Objective-C in particular, and discusses it from the point of view of a Java programmer. He also takes a brief detour from this topic to share his views on swing apps for Mac OS X.
Currently, the Mac Devcenter is running a series of articles by Mike Beam titled Programming with Cocoa. This series is geared toward looking at Mac OS X's Cocoa APIs as expressed in Objective-C. This is only natural given that Objective-C is the native language of Cocoa, but since I am approaching this article from the perspective of a Java coder, I've been experimenting with Cocoa's Java APIs.
There is a lot of general documentation on Cocoa at Apple's Cocoa Developer web site. And the tutorial on how to use Cocoa in Java is a good start. It shows the power of Interface Builder and Cocoa, and yet is an easy read. I had the sample Temperature Converter up and running in no time. But, after that point, the remaining Java-oriented documentation consists mainly of the Application Kit and Foundation API references. And worse, these references are incomplete ports of the Objective-C documents. For example, the following sentence comes from the Java application references for the NSEvent class:
"
NSWindowandNSApplicationdefine the methodnextEventMatchingMask:untilDate:inMode:dequeue:, which allows an object to retrieve events of specific types."
The above makes very little sense to a Java programmer unless they have some experience with Objective-C message-naming conventions. Somebody that had never seen Objective-C might translate the above to a Java-ish method of nextEventMatchingTask(untilDate, dequeue) and looking in the documentation for NSApplication, there is no exact method of this signature. Instead, there is a method signature of nextEventMatching(int mask, NSDate expiration, String mode, boolean flag). At this rate, I'd rather just have sparse Javadoc-generated documentation.
Don't get me wrong, after my initial foray into Cocoa, I'm impressed. Interface Builder is a dream to work with and the performance of Java driving the native Cocoa widget set is impressive. There is lots of promise here, but right now the documentation is not geared toward Java programmers. To make heads or tails of it, you end up learning quite a bit of the Objective-C language. There is nothing wrong with knowing another language, and I've found Objective-C to be fascinating. However, a lot of work remains to be done before typical Java programmers will be able to easily use the Cocoa APIs.
Because of Apple's weak Java-based Cocoa documentation, I have had to get somewhat familiar with Objective-C in order to explore Cocoa-Java programming. Even though they are both highly object-oriented languages, there are quite a few differences between the two.
The most obvious difference between the languages is one of syntax. One of the early strengths of Java was that it used a syntax for method declarations that was very similar to C functions. Objective-C, on the other hand, uses a syntax that is much closer to Smalltalk (the grandaddy of object-oriented languages). In an earlier installment of this series, I quoted the following example from the Apple NSEvent documentation:
"
NSWindowandNSApplicationdefine the methodnextEventMatchingMask:untilDate:inMode:dequeue:, which allows an object to retrieve events of specific types."
A Java programmer not familiar with Objective-C or Smalltalk will look at that paragraph and scratch his head. If you don't know the syntax, it is hard to parse out what the method name is and what its parameters are. It helps tremendously to look at the actual method signature from deep down in the documentation (or in the header file) where we find out that the method really is:
- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expirationDate inMode:(NSString *)mode dequeue:(BOOL)dequeue
This method signature, even though it is still sporting all the colons and has pointer stars, is quite a bit more meaningful to our Java programmer. It has parameter names and the types of objects or data that the parameters expect. And it is a lot easier to map its Java equivalent:
nextMatchingEvent(int mask, NSDate expiration, String mode, boolean flag);
|
Previously in this series: |
The lesson? Make sure to dig deeper into the documentation or even take a look at the actual header files so you can better map what Objective-C's methods are doing into your way of thinking. At least until you get used to the different syntax.
A less obvious, but larger difference between the languages is that Objective-C is actually much more dynamic at runtime than Java is. Most of the time in Java, you have to know the type of the object that you are working with in order to call methods on that object. For example, you have to know that you have a reference to an object of type java.awt.Component before you can call the show() method. In Objective-C, quite simply, you don't. You can simply call the show method. More accurately, you can send the show message to an object and if the object knows how to, it will show itself. This level of dynamic binding is one of the things that makes Cocoa UI Programming and Interface Builder work well.
To be sure, the same sort of effect can be had in Java using the Reflection APIs. Many of the programs that I have recently written in Java use Reflection heavily and perform the same kind of magic, but with much more code. Here's an example of asking a Java object to show itself:
try {
Class objectClass = object.getClass();
Method showMethod = objectClass.getMethod("show", null);
showMethod.invoke(object, null);
} catch (NoSuchMethodException nsme) {
// do something
} catch (IllegalAccessException iae) {
// do something
} catch (InvocationTargetException ite) {
// do something
}
So, what are the big shortcomings of Objective-C if you have a strong Java background? The number one issue that I have run into is memory management, or the lack of it compared to Java's garbage collection. Stepwise has published some nice rules for memory management in Cocoa, but it is still a pain. The second issue is the lack of package namespaces like com.oreilly.*. Packages, and the package-protected level of method visibility, have been a lifesaver in several of my Java projects. Naming conventions such as the NS prefix used in the Foundation and Application Kit libraries are not as good a solution.
Even so, Objective-C has turned out to be a lot more interesting than I initially thought it would be. I'll be spending quite a bit more time playing with Cocoa using both the native Objective-C bindings and the newer Java bindings. When I've formed up some more opinions, you can be sure I'll post them here.
|
The most frequent question people have for me when I tell them that I am developing Java on Mac OS X is, "How well do your applications run?" And the answer is that my experiences have been really good -- stunningly good in fact. But then, most of my applications have been faceless server applications and most of the cross-platform problems in Java hit GUI applications. As luck would have it, a few of my friends that develop GUI applications have started developing on Mac OS X, as well and I have good news to report.
|
|
One of these friends, Greg Murray, has been working on his own Java code editor for the past year or two in his spare time -- that is, when he is not working on the J2EE Blueprints at Sun. As he makes improvements, it is turning into quite a decent tool for hacking on Java code. You can find this program, called MightyJ, at http://www.mightyj.com/. Greg originally developed this application on Linux and Windows, but after seeing my OS-X-based laptop and its JDK 1.3 implementation, he took the plunge and bought a Cube and started hacking on MightyJ using OS X. And his experience was almost seamless. They only place he had to change code was in some custom components he built himself. A few days later, he was raving about how MightyJ looked just like a native OS X app and was impressed by the lack of problems when running it on OS X. Now, his biggest complaint is that he doesn't have a Mac OS X machine at work.
You can find screenshots of MightyJ running on OS X at http://www.mightyj.com/screen_shots.html.
Even better, it seems that Swing on OS X is just going to get better. Apple has been hard at work at figuring out how to get hardware acceleration behind Swing to drastically improve performance and has been showing this technology off at Apple's Worldwide Developers Conference (WWDC). In demos, it turned previous choppy resize operations into silky smooth ones. This technology will be shipping as part of the upcoming Java update, but will not be turned on by default as it is not quite ready for primetime. You can bet that I'm digging in to find more information about this technology and will get details out as soon as I can.
Earlier, I discussed a few of the differences between Objective-C and Java. Now I'm going to take a look at a couple of things that are annoying, and sometimes painful, about working in Objective-C. Especially when coming from a Java background.
First, Objective-C is based on the strict ANSI C standard. This means that you are limited to declaring new variables to the top of a block of code. What happens in practice is that the following code (a snippet that all Java programmers have used a bazillion times and have automatically programmed into their fingertips) will not compile:
for (int i = 1; i < j; i++) {
// do stuff
}
Instead, you need to write your code to look something like:
int index;
for (index = 1; index < j; index++) {
// do stuff
}
This looks innocent enough in the example above, but most methods have a page or two (hopefully not more!) of implementation. In real life, the example looks more like the following:
int index;
// Lots of code in method...
[[NSColor whiteColor] set];
NSRectFill(rect);
for (index = 1; index < j; index++) {
// do stuff
}
Declaring an index a page before the for loop that uses it is quite annoying. Or declaring any short-lived variable too far from where it is being used is a sure way to run into readability problems. At WWDC, it was mentioned that this problem will likely go away as the C support is upgraded. Until that happy day, there is a workaround. Simply open a new block of code with curly braces. Here's an example:
// previous code in method...
[[NSColor whiteColor] set];
NSRectFill(rect);
{
int index;
for (index = 1; index < j; index++) {
// do stuff
}
}
The second issue is one that is not picked up the by the compiler. It is the accidental case of using an `=` assignment operator in an if(condition){} statement instead of the `==` comparison operator. There have been at least three cases in the last few days where the following code caused non-obvious problems in my programs:
if (answer = NSAlertDefaultReturn) {
sp = [NSSavePanel savePanel];
[sp setRequiredFileType:@"expenses"];
answer = [sp runModal];
// ...
}
The above code will compile just fine, but trying to figure out what is happening at runtime can get a little tricky. Even if you have a hint of the problem, having to scan pages of code looking for a single missing '=' character can make your eyes cross.
Are these issues enough to keep me from further experimentation with Objective-C? Nope, not at all. But they do constantly annoy me as I explore the language and the Cocoa frameworks. They take a little bit of the shine off an otherwise enjoyable experience. Just enough to make me really appreciate some of the polish that the creators of Java put into the language and its semantics.
James Duncan Davidson is a freelance author, software developer, and consultant focusing on Mac OS X, Java, XML, and open source technologies. He currently resides in San Francisco, California.
Return to the Mac DevCenter.
Copyright © 2009 O'Reilly Media, Inc.