I’ve already described how misfortune and adversity left Apple with a new OS platform free of legacy constraints; and I’ve also discussed how Microsoft had failed to do the same, choosing instead to hobble its new OS with way too much legacy baggage.
Now, let’s look at why I’m even considering the big switch: what has Apple done with its platform to make it so appealing? Of course, if you’re already writing software for the Mac, then I’m not going to tell you anything you already don’t know. But all of this was new to me, because it wasn’t until I became so thoroughly disappointed with Windows that I really looked in earnest at what the Mac had to offer. My mistake.
The NeXT connection
First, let’s take a brief look at what Apple got when it bought NeXT, and at some of the important bits of NeXT technology that live on today. When Apple bought NeXT, it inherited what was in many ways quite an unusual OS. Most operating systems are written in C and define all the APIs and extension points of the OS in C terms. As I said in part 2, this is because C’s simplicity means that virtually all programming languages can call C APIs without too much difficulty. C is very much the of programming languages—an adequate, though imperfect, lowest common denominator for exposing OS functionality to applications. NeXTstep was (and remains) unusual, because NeXTstep bucked this trend. NeXTstep didn’t eschew C altogether, and indeed, many low-level features did use C APIs—its use of BSD UNIX ensures that much, as UNIX and C go hand-in-hand—but it also used a dynamic, object-oriented language, Objective-C, for many things.
Obj-C is a kind of hybrid between C and the language Smalltalk. Smalltalk is a niche language that has never been widely used, but it has particularly strong support for one approach to object-oriented programming, called message-passing. In message-passing OO, objects send each other messages to perform actions. When an object receives a message, it can examine it and choose to respond to it, ignore it, or send it somewhere else. Whether an object knows how to handle a message isn’t known until the program is actually running. The program code that the developer writes needn’t contain any particular restriction on which messages are sent to which objects, and indeed the messages that an object might respond to could also vary when the program runs. Although this dynamic behavior is not especially unusual in scripting languages, it’s much less common in system programming languages. The message-passing approach is quite unusual in the OO world; most OO languages (including all the common ones: C++, Java, C#) use a different model for their OO facilities, one based on the Simula language instead. This approach is much stricter; whether a particular function can be called on a given object is determined when the program is compiled, not when it’s run.
The Smalltalk-inspired object oriented parts of Obj-C are quite independent of the C parts. Any C program can be compiled by an Obj-C compiler; using C APIs from within Obj-C programs is trivial, because Obj-C can do everything that C can do. Going the other way is much harder; many languages simply have no facility for the kind of things that Obj-C takes for granted, especially when it comes to some of its more complex features.
Coupled with this unusual programming language was an API that exploited the unique properties of the language. The API was split into a number of “frameworks”, each of which covered a specific area of functionality. Although these frameworks have evolved over time (NeXTstep’s history was a lot more complicated than I have described here, and this history influenced the development of the API considerably), there are two in particular that are of paramount importance, because they are what makes up Cocoa.
The Cocoa API has two parts; “Foundation Kit” and “Application Kit”. Foundation Kit provides basic functionality common to virtually all programs: string manipulation, container/collection classes, XML parsing, file I/O, and so on. Application Kit is what provides GUI programming facilities. It’s here that Mac OS X (and NeXTstep before it) sets itself apart from platforms such as Win32.
The people who developed Smalltalk also devised a design approach for writing GUI applications called “Model View Controller” (MVC). The idea of MVC is to separate an application into three parts; the Model, which represents the things that the application actually cares about (e.g., documents in a text editor); Views, which contain the visual representations of the data in the application, such as buttons and text boxes; and Controllers that link the two and ensure that changes in one are properly propagated to the other. The Model is common to all the Views, with each View representing a different part of it, and each View has a corresponding Controller. Although this pattern of writing applications is quite widely used, it is particularly important to Application Kit. Application Kit bakes in a lot of MVC functionality, all but forcing software to be structured in this way.
What that means today
Cocoa applications get a lot of things for free, just by virtue of being Cocoa applications. The predefined Models, Views, and Controllers provide powerful built-in capabilities that can be used and extended by software. The class NSTextView, for example, provides a consistent multi-line text editing View, complete with multiple fonts, font sizes, and text colors, along with red and green wiggles underlining for spelling and grammar errors (respectively) with unlimited undo/redo. As new abilities are added to the NSTextView class, software that uses it can pick up these abilities automatically.
The NSTextView is not some monolithic and inflexible class, either; it hands off different areas of responsibility to other classes. For instance, the way that text flows in an NSTextView is governed by a class named NSTextContainer, which performs line-wrapping and similar tasks. If, however, NSTextContainer doesn’t do what you want (perhaps you want to be able to put arbitrarily shaped objects into the text and have the words reflow around them) you can replace it with your own class. As long as it responds to the same messages, it will work as a drop-in replacement.
The customization mechanisms for the classes that Apple provides depend strongly on Obj-C features. Although the subclassing approach found in most OO languages is an option, it is not the only one. The ease with which Obj-C can forward messages to different objects means that (where one object passes responsibility for a behavior to another object) is very easy to express and support. Unlike with, say, Java or C++, the delegated-to object needn’t implement any specific interface or extend any particular base class; it can just listen for the individual messages that it’s interested in and ignore everything else. This makes replacement or modification of individual operations quick and easy.
To make best use of this framework, you also need to look at Apple’s development tools, in particular Interface Builder, which is Apple’s application for constructing user interfaces. Interface Builder is another NeXT artifact; it ultimately dates back to the 1980s and was one of the first development tools that allowed user interfaces to be built using drag-and-drop and a mouse. Within Interface Builder, Views objects can be arranged and connected together to construct an interface for your application. Once you have your View objects, you add a Controller to tie the View to your model, to propagate changes from one to the other. Finally, you plumb individual fields into their respective Views, and wire up buttons and other interactive elements to actions, so that things actually when you use the UI.
Interface Builder makes it very easy to put together user interfaces. If you have absolutely no design skills, you’re probably not going to get a work of art, it’s true. But equally, it’s unlikely to look terrible. The Views that come with the system are the ones used everywhere else in the OS, and they bring a lot of behaviour with them. Appropriate guides appear in order to assist with lining up objects in the right way, and just following these should prevent anything too horrific.