Contents

  1. Mac OS Development: resources for getting started in Mac OS development.
  2. Application Frameworks: a discussion of one of my pet projects and its history.
  3. Language Considerations: a comparison of object-oriented languages.


Mac OS Development

The Macintosh Operating System brought the Graphical User Interface (GUI) to desktop computing. Sixteen years later, GUIs are common on all systems, the most popular of which is certainly Microsoft Windows. Nevertheless, Apple has retained a faithful following of developers and users. I have been a "Mac person" for several years now, and despite the aging operating system foundations, I enjoy developing software for the Apple's OS, and am looking forward to the coming release of Mac OS X, Apple's "next-generation" operating system which incorporates long-overdue modern features such as preemptive multitasking and protected memory.

Despite its problems, my platform of choice for development has been and remains Mac OS. I have invested considerable effort into learning the Mac OS Toolbox APIs and have created many pieces of software based on these foundations. While Microsoft Windows is tempting because of its huge installed user base, the kinds of software I have developed are best-suited to the Mac OS, and as a result I have spent much less time writing software based on the Microsoft Foundation Classes/Win32 APIs.

Learning to write Macintosh software is no harder than writing programs for Microsoft Windows. In fact, the Mac OS Toolbox is really quite similar to the Win32 APIs. (It's actually no surprise, considering Microsoft programmers were familiar with the Mac OS Toolbox.) Here are some resources to help you get started:


Application Frameworks

As every software developer knows, it is most desirable to concentrate on writing code that makes our applications unique and exciting. It is not desirable to write code to manage mouse clicks and update windows. Microsoft Windows solves this problem with the Microsoft Foundation Classes. Mac OS, on the other hand, has two application frameworks available: MacApp, and Metrowerks Powerplant. Unfortunately, both of these frameworks are quite heavyweight, in the sense that they incorporate a lot of features and code that you'll probably never use. In addition, all three of the frameworks I've mentioned have design flaws that make them "unfriendly."

In about January of 1998, I finally decided to develop my own application frameworks. Going into it I knew it was a huge task, and a lot of issues had to be considered. Here is a short list of my original criteria for an application framework:

After looking carefully at the criteria I had laid out, I looked at several application frameworks to see how they solved these problems. The frameworks I investigated included the three I already mentioned, as well as Apple's Cocoa APIs (formerly OpenStep/Yellow Box APIs, originally developed at NeXT) and Sun's Java classes. The result was to break my application framework into three main pieces:

The reason for breaking my framework into three pieces was mostly because not all applications need all of the features. While all applications must include the Foundation Library, a UNIX command line application (which lacks a GUI) does not require either of the other two libraries. Similarly, a "faceless" Mac OS application would not need the Application Library since it does not have a user interface.

Reference Counting

One of the most important concepts I've incorporated into my framework's base class is reference counting. Reference counting is a simple mechanism which allows objects to have multiple "owners" and solves the problem of when it's safe to dispose of an object. Reference counting is an easy concept to implement (far easier than, say, generational garbage collection used by Java virtual machines) and has the potential to greatly reduce memory problems in your code. Reference counting schemes can run into problems in situations such as doubly linked lists, but as long as the developer is aware of these situations, the mechanism is excellent for general use.

My implementation is derived from that used in Objective-C. There are a few rules of using my implementation. First, when you create an object using the new operator, the object's reference count is set to 1, meaning that the code which created the object owns it. Second, you may not use the delete operator to dispose of objects. Rather, you must call the object's retain() method. Recall that in my frameworks, all objects should be derived (either directly or indirectly) from my base class, called TObject. Thus, every object inherits the following two methods:

Once each of an object's owners gives up its reference by calling the object's release() method, the object will be automatically disposed of. Note that many objects (such as locally created objects) may only have one owner, but some objects may have several owners.

Here is an example of a piece of code that uses reference counting. Note that the class MyObject is derived from TObject, and just includes reference counting abilities.

void MyApplication::myMethod() {

MyObject *object = new MyObject(); // create a new object

object->doSomething(); // invoke one of the object's methods

nonMemberFunction(object); // call a non-member function

object->release(); // done with it now

}

Autorelease Pools and Temporary Objects

In addition, I've adopted the Objective-C concept of autorelease pools which helps manage "pools" (or collections) of objects. Many classes (the string class for example) have the capability of creating "temporary" objects. These are extremely useful. Imagine the following scenario: You create a string object and proceed to perform some other operations, one of which generates an error which causes your code to jump to the error handling code without disposing of the object. Normally, the string would have been disposed of, but the unexpected jump to the exception handler caused your program to skip the code that would have released to object.

With temporary objects this is not a problem. Temporary objects introduce the idea that objects have a limited lifetime. Since GUI-driven applications run in a continuous loop, it is quite simple to dispose of all temporary objects at the end of the run loop. This brings us to the concept of Autorelease Pools. Essentially, an Autorelease pool is a container which holds a list of all objects that need to be disposed of at the end of the run loop. When a temporary object is created, it is added to the autorelease pool. The program can then use that object and not worry about disposing of it when it's done with it, because the object will automatically be disposed of. In the above example, if the object was a temporary object, the exception handling code would take care of properly disposing of any temporary objects created during the run loop, and thus eliminate that potential memory leak.

The attentive reader is probably wondering, "what if I don't want that object to be disposed?" The answer is this: if you want to save a reference to an object, you simply call its retain() method. Even though that object will be released at the end of the runloop, calling retain() indicates that it has another owner, and thus the object will not be disposed. Only later when you explicitly call the object's release() method will the object be disposed of, unless, of course, the object's retain() method has been called again by some other piece of code.

Please note that I have greatly simplified these concepts in the interest of space. When I make these frameworks public, I will include complete documentation which will explain how these concepts can be adapted and used to produce customized behaviors.


Language Considerations

This section is not yet complete. In it I will discuss the strengths of various object-oriented languages. I will also address the Fragile Base Class problem and discuss some solutions.


Updated January 19, 2000.

E-mail: jkrueger@cs.wisc.edu