About | ACP | Buy Stuff | Industry Watch | Learning Curve | Newsletter | Search | Test Drive
Home » Learning Curve » Red Hat Diaries

Form or Function

Why OO works and the others fail.

Get It

Try It

People get used to the systems they use. Ultimately they feel they prefer them. And ultimately find it difficult to move to and permanently use anything else.

Anyone using any platform is both liberated and limited by the platform's architecture. What 'kernel' is found underneath is irrelevant in this context. But for the record: Apple's Mac OS X, the BSDs, and Linux all have excellent kernels impervious to the slings and arrows of outrageous Windows malware.

Yet the Linux 'GUIs' (desktops) share way too much with Microsoft Windows. Here's a look at application development on Windows, an intimation of how it will proceed as well on Linux, and finally how it works in a true object oriented environment like Mac OS X.

Windows Application Development

Windows borrows a lot from other environments when it comes to interface architecture, using the so called event driven programming model. Event driven programming differs from traditional programming in that it doesn't control flow - it doesn't determine what's to be done next or prompt the user with specific questions. A traditional program might look like this.

C:\Documents and Settings> printdoc
Welcome to printdoc! Please give the full path to the document you want to print.
C:\Program Files\myfile.doc
Sorry, that is not a valid file path. Please try again.
How many copies of your document do you want to print?
Sorry, valid replies are in the range 1-10! Please try again.
Press enter to print 10 copies, press Esc to abort.

And so forth. The user starts the program and the program takes over. That's not the way it works in event driven programming. Not anywhere.

Resources. All GUI programs need resources and Windows is no exception. Resources are graphic elements such as menus, dialog templates, icons, other images, and so forth. The Windows application developer must first sketch out the application menu, choosing applicable titles for all the items and associating a numerical value with each. This is done in a plain text file.

Menu items will hopefully also have keyboard shortcuts. The Windows application developer creates a separate accelerator table. This too is plain text (commonly stored in the same source file as the menu). The accelerator table correlates keyboard shortcuts with numerical values from the menu already created.

Working with raw numerical values can be confusing and difficult so the developer will create macro definitions to correlate these values with something more easily recognisable.

#define FILE_NEW         0x0010
#define FILE_OPEN        0x0011
#define FILE_SAVE        0x0012
#define FILE_SAVEAS      0x0013
#define FILE_PRINTSETUP  0x0014
#define FILE_PRINT       0x0015

And so forth. Two file menu items commonly found on Mac OS X will be conspicuous in their absence: Close and Save All. Close doesn't make any sense as closing the window closes the application and Save All doesn't work either as there's only one 'document' to save at a time.

Then too the recurring prompt in Windows - 'do you want to save before you start a new file' - won't be there either as OO platforms aren't crippled by a single reusable window for all editing - they just open new windows as they need them.

Application code. The developer must now write the code to hold the interface and the program logic together. Windows requires the developer to write the code for a 'message pump' inside the application. The logic of this message pump is as follows.

  1. Process toolbar updates if the message queue is empty.
  2. Send the message for special processing if it's a 'dialog message'.
  3. Send the message for special processing if it's a keyboard shortcut.
  4. Sit and wait for (and block on) the next incoming message.
  5. Dispatch the message to the right window procedure.

Window procedures are a chapter unto themselves. They're structured as ordinary (nested) C 'switch' constructs. Window procedures are called with four parameters.

  • hWnd. Literally: a 'handle' to a specific window. An opaque value used as a reference in all subsequent calls.
  • message. A UINT - an unsigned integer of machine register length. This is the actual (numerical) message being sent.
  • wParam. Short for word parameter. Today it's no longer of 16-bit 'word length' but 32-bit instead.
  • lParam. Short for long parameter. Today as yesterday it's 32-bit.

The most common 'message' value - the one pertaining to the menu the developer's written - is WM_COMMAND. Here the developer will branch to yet another nested switch construct to ferret out the numerical value actually being sent.

switch (message) {
/* * */
    switch (LOWORD(wParam)) {
    case FILE_NEW:
        /* * */
    case FILE_OPEN:
        /* * */
    case FILE_CLOSE: // This makes no sense on WINDOWS!
        /* * */
    case FILE_SAVEALL: // Not yet implemented - this is WINDOWS!!1!
        /* * */

And so forth. The developer also needs to write specific procedures for each panel (dialog) in the application.

At each 'case' point in the above snippet (and in the dozens more the application will need) the developer needs to either write the code that will handle the message or call external functions to handle them.

At the end of the run - when the user decides 'enough is enough' and tries to close the application window the window procedure will get a sentinel call. After performing routine cleanup the procedure must then call PostQuitMessage() which breaks the message pump loop.

The next time the message pump (see above) gets a sentinel message of its own the code loop will break. At this point a few more lines of trailing code (which the developer must also write) will perform the final cleanup so the app can exit.

Startup code. The developer needs to do two things at this point.

  1. Declare and define a basic 'window class' for the application as a whole.
  2. Initialise everything that needs to be initialised and get that main window onscreen.

After that it's just to 'sit back and wait' - the user's input (and various types of input from the system) will accrue to the thread-specific message queue outlined above and be processed by the application.

Mac OS X (Cocoa) Application Development

Development on the Mac is always visual - which is a good thing as it's graphical interfaces the developer deals with. Xcode (formerly the NeXT Project Builder) starts things off by providing an application template. All IDEs offer application templates today (or they should offer) but things are a bit different away from Windows and open sauce.

Things start falling into place once the developer's chosen the type of application and a name and path for it.

The developer will typically open the 'Resources' tree on the left and double click the 'NIB' file found therein. This starts the companion Interface Builder which is used to sketch the layout of the application. Application windows aren't normally built in this way on Windows.

The Cocoa developer uses Interface Builder (IB) to put controls - push buttons, lists, et al - onto the application window. The controls are then 'wired' (using drag-drop) to the class code running the show. The controls themselves will generate actions - special messages sent back to specific methods in the controller class.

The controller class will in turn have outlets - pointers as it were in its class definition set already in Interface Builder (drag-drop again) to reference the window's controls.

The Cocoa application template will also come with a menu ready to run. There are no menu declarations here or accelerator tables - it's all in place. And because it's object oriented the menu items apply everywhere. You use the same 'Copy' menu item (and the same ⌘C shortcut) everywhere.

There is no explicit menu resource construction; there is no such thing as an accelerator table or anything like it; there is no need for 'window procedures' or 'message pumps'; there is no application 'init code' per se. The developer merely sketches the app in Interface Builder, connects the controls to the class that will subsequently be written, connect outlets from the class to the controls, and gets to work writing the code.

Cocoa document based applications can be run and tested 'as is' with no code written and nothing yet designed in Interface Builder either. And each control in the 'GUI' leads to a single 'action' sent directly to a method in the class code. That's it.

No window procedures, no 'switch' constructs, no arbitrary macro definitions for 'man made' menu items with arbitrary numerical values - none of that. And the most important of your menu items are already connected. Even the 'about box' is free.

All of which might lead a seasoned developer from another platform to suspect there's a lot of gunk (and bloat) going on under the surface. But it isn't so. It's not at all what one encounters on Windows. The 'NIB' file itself represents 'freeze dried' class code that's 'unarchived' at runtime and automagically put in contact with the application code. The 'NIB' itself represents application code - except the developer doesn't 'write' it: the developer 'sketches' it.

As for window resizing: no need to worry about moving the controls around. It's all taken care of automatically.

Some other things the Mac OS X Cocoa developer never needs to worry about:

  • File names. Normally the application won't even see the names of the files being edited. The user will but the application code won't. It doesn't need to - it's all automatically taken care of by the document controller.
  • Buffers for file paths. It stands to reason if the code won't bother with file names it won't need buffers for them either. There's no OPENFILENAME here, thank you.
  • Remembering if a file buffer is 'dirty'. No need to keep a flag to save changes - it's all automatically taken care of by the document controller.
  • Saving files on application exit. There's no need to remember any of the above on application exit either - if files need to be saved then the document controller will prompt the user and call the application code if need be. No worries.

Further Reading
Red Hat Diaries: The New Open Sauce Desktops

About | ACP | Buy Stuff | Industry Watch | Learning Curve | Newsletter | Search | Test Drive
Copyright © Rixstep. All rights reserved.