TweetFollow Us on Twitter

OOP Architectures 2
Volume Number:7
Issue Number:3
Column Tag:OOP Architectures

MacApp and THINK Class Library

By Larry Rosenstein, Apple Computer, Inc.; Joseph S. Terry, Jr., Ajalon Corporation

Part Two

Object-oriented Design (OOD) ...

“Design is the most difficult and important task of Object Programming (OP) and very few professional software engineers do it well.”

That sentence began the first of this two-part(read long) article and it bears repeating. Goods tools in and of themselves do not produce reliable, well designed products, well trained software engineers do.

In this second part we will explore the execution of commands which are mostly menu choices or button clicks, look at general flow of control from one class to another, clear up some confusion about exactly what does go on under low memory conditions (and doesn’t), take a look at printing, using background tasks or chores, error handling, and a summary of the things to remember when programming with any class library.

The last seven sections are the ones we’re covering in this second part. The first five sections were covered in the January 1991 MacTutor.



3 - HOW THINGS WORK TOGETHER: An Example Message Trail
















Larry Rosenstein

Apple Computer, Inc.


A large part of an application’s code is devoted to processing commands. In MacApp, commands are represented by the TCommand class. TCommand is not only used to factor out commands from the rest of the application, but also to encapsulate the information necessary to undo the command (if the need arises).

There are 4 methods of TCommand related to performing actions: DoIt, UndoIt, RedoIt, and Commit. When the command is first performed, MacApp calls the DoIt method. DoIt is responsible for saving information in case the command is undone and performing the command.

UndoIt is called if the user selects the Undo menu item. RedoIt is called if the user selects Undo again. DoIt and RedoIt are similar and often share code. If the user selects Undo a third time, then MacApp calls UndoIt again, and so on.

The purpose of the Commit method isn’t as obvious. It is called when the command can no longer be undone (e.g., the next command is about to be performed) and the command hasn’t been undone. This gives the command object one last chance to affect the document before it is freed.

Commit is used in cases where the command isn’t easily reversible. In a drawing program, moving shapes is easily reversible. The command object simply remembers the offset and moves the shapes by the same amount in the opposite direction. A command that changes the fill color, however, isn’t easily reversible. Reversing the command requires that the program remember the old color of each affected shape. This could take almost as much memory as the entire document.

In this case, the command could be implemented using a filter. When the user changes the fill color of one or more shapes, the color stored in the shape objects isn’t changed immediately. Instead the program remembers which shapes were affected, and what color they were changed to. When drawing the affected shapes, the program uses the color in the filter. To the user the shapes have changed color.

Undoing the command is now easy, because we simply remove the filter. The shape objects are then drawn with their original color. Eventually, however, the shapes’ colors must be permanently changed; this would be done in the Commit method.

Now that we know how command objects work, where do they come from? A MacApp application creates command objects in response to user actions. The 3 main cases are menu selections, keystrokes, and mouse clicks.

Menu selections and keystrokes are handled in a similar manner. MacApp takes case of handling the menu or extracting the character, and calls the DoMenuCommand or DoKeyCommand method. The target event handler gets the first chance at handling the event; control passes along the target chain until it reaches the object responsible for handling the event. At that point, the event handler object creates the appropriate command object and returns it to MacApp.

In the case of a mouse click, MacApp locates the view in the hierarchy on which the user clicked, and calls the DoMouseCommand method of that view. DoMouseCommand creates a command object and again returns it to MacApp. This command object tracks the mouse, and (usually) performs the command when the user releases the mouse button.

There are 3 method of TCommand involved with mouse tracking:

• TrackMouse, which receives the current position of the mouse and processes it,

• TrackFeedback, which draws and erases the temporary feedback while tracking,

• TrackConstrain, which modifies the mouse position before the other methods see it, in order to implement constraints (e.g., constraining a shape to be a perfect square).

MacApp calls these methods as the user moves the mouse. The tracker doesn’t have to worry about automatic scrolling (if the user moves outside the window). TrackMouse returns a command object, which becomes the new tracker. (In most cases, the command object returns itself, but it is possible for one tracker to “hand off” to another.)

When the user releases the mouse, TrackMouse returns the command object that executes the mouse command. For example, if the user is sketching a new shape, this command object is responsible for adding the shape to the document. (Normally, the same object performs the command as tracks the mouse.)

Not all menu commands or mouse clicks result in significant changes to the document. In those cases, MacApp provides a global command object (gNoChanges) that the application can return. It is also possible to create a custom command object and mark it as one that doesn’t change the document. (One advantage of the latter approach is that the command will be performed from the main event loop, rather than from a point several procedure calls deep. This may be preferable from a memory management standpoint.)



Memory management is one of the more difficult aspects of Macintosh programming. Applications are only given a limited amount of memory to work with, so it is always possible to run out. If this happens while trying to load a code segment, for example, the result is the dreaded System Error alert.

MacApp cannot handle all the details of memory management. It does provide a framework that you can use. One goal of the memory management framework is to prevent a System Error because a code segment or other resource can’t be loaded. Another goal is to ensure that the user can always save the document and quit.

MacApp’s memory management framework is based on reserving RAM space so that it can be used at critical times. MacApp maintains 2 reserves, one for memory associated with the document (“permanent” memory) and one for “temporary” memory. MacApp maintains a global variable to indicate whether memory being allocated is temporary or permanent.

There is no distinction between permanent and temporary memory as far as the Macintosh Memory Manager goes. The difference is only significant in what happens when memory is low. When memory is low, MacApp will release the appropriate (permanent or temporary) reserve in order to allow the request to succeed. This is done by installing a procedure that the Memory Manager calls when an allocation request can’t be immediately satisfied.

Requests for temporary memory must always succeed, since the alternative is likely to be a System Error. Permanent requests are allowed to fail; MacApp assumes that the programmer will check the result of these allocations and fail gracefully if one fails.

Most of MacApp’s memory management framework involves managing the reserves. It is important to have sufficient reserve available, so that the application doesn’t crash, but it is also important not to monopolize that memory unnecessarily, so that it can be used.

The size of the reserves is normally set based on resources (although you can set them programmatically as well). The permanent reserve is generally small, since it isn’t intended to satisfy every request. The temporary reserve, on the other hand, must be large enough to cover the maximum amount of temporary memory in use at any one time.

In practice, this number ends up being the maximum size of the code segments locked down at any one time. (With proper segmentation, this number is only a fraction of the size of all the code segments.) Sometimes you have to include memory used by defprocs, packages, print drivers, etc.

The MacApp debugger provides utilities for determining the maximum code usage. You can have the debugger break when each segment is loaded, or when a new maximum usage is reached. Then you can list the names of the loaded code segments and enter then into a ‘seg!’ resource in your application.

When the application starts up, MacApp adds up the sizes of all the segments listed in all the ‘seg!’ resources and adds that value to the temporary reserve. In addition, MacApp examines all the resources of type ‘mem!’. Each of these resources contains values that are added to the temporary reserve, the permanent reserve, and the stack size.

Once you have specified the sizes of the reserves, MacApp takes care of ensuring that the reserves are available. For the permanent reserve, MacApp allocates a handle of the required size. If a permanent allocation cannot be satisfied, then MacApp releases the entire permanent reserve.

You can test to see if the permanent reserve has been released by calling the function MemSpaceIsLow. MacApp does this during its idle processing, and calls the method TApplication.SpaceIsLow is the reserve is gone. By default, this method displays an alert. In addition, MacApp disables certain commands (New , Open , etc.) if memory space is low; you are responsible for doing a similar thing for the commands that you handle.

Managing the temporary reserve is more complicated. MacApp could allocate a large handle the size of the reserve. Unfortunately, this would often waste memory. For example, suppose your application needs a temporary reserve of 100K to load code segments A, B, and C. If none of the segments is in memory, then MacApp would have to allocate a 100K handle to make up the reserve. If segment A is already in memory, however, then the size of the handle only needs to be the total of the sizes of B and C.

In its implementation, MacApp total up the sizes of code segments, packages, and defprocs that are already in memory, and subtracts this sum from the desired temporary reserve. If the result is greater than 0, then MacApp allocates a handle to make up the difference.

MacApp doesn’t keep track of every resource as it comes and goes. If you think about it a minute, the integrity of the temporary reserve is only critical when a permanent request is made. That’s because you don’t want to satisfy the permanent request at the expense of reducing the temporary reserve. So MacApp doesn’t have to check the temporary reserve until the temporary/permanent flag is set to permanent.

This memory management framework is a good example of how MacApp can embody accumulated Macintosh programming knowledge, and make it available to other programmers. The basic approach of maintain reserves and managing them was first implemented in Apple’s Macintosh Basic, and re-implemented in the first version of MacApp.


Printing is another feature that can be difficult to implement on the Macintosh. It requires that you interact with the Printing Manager, and that you follow a definite series of steps. This makes it ideal for an object-oriented approach such as MacApp’s.

In a MacApp program, you rarely have to write any code to implement printing in your application. Once you have defined a view object that can draw on the screen, MacApp uses the same view object to “draw” on the printer. MacApp takes care of the various printer dialogs for you.

All the printing code is encapsulated in the TStdPrintHandler class. When creating your view object, you can make it printable by associating it with an instance of TStdPrintHandler.

Although most application don’t need to modify MacApp’s printing behavior, TStdPrintHandler provides many opportunities to do so. A simple change is to set the page margins. This is done with a call to TStdPrintHandler.InstallMargins.

Another common change is to modify the way MacApp breaks the view into pages. By default, MacApp computes the part of the view that can be displayed on each page, based on the desired margins and the printer’s characteristics. In then divides the view into chunks of that size. If you are implementing a text processor or spreadsheet, however, you would want to break the pages between lines of text or spreadsheet cells.

Before finalizing a page break, MacApp calls the view method DoBreakFollowing. You can override this method and move the page break back to a convenient boundary. You can also implement manual page breaks by overriding the same method. It is also possible to change the way in which page breaks are drawn on screen by overriding TView.DoDrawPageBreak.

A final printing variation is to add elements to the page that aren’t drawn on screen. By default, MacApp reproduces the entire view on the printed page. If you wanted to draw page numbers or headers, however, you could override the method TStdPrintHandler.AdornPage. This method is called once for each printed page, after the main part of the page has been drawn.


MacApp provides a simple framework for performing tasks in the background. This takes the form of the TEvtHandler.DoIdle method, which MacApp calls repeatedly when there are no user events pending. The TApplication, TDocument, and TView classes are all subclasses of TEvtHandler, so any instance of those classes can receive idle time. Additionally, you can define a special subclass of TEvtHandler to do other idle processing.

Instances of TEvtHandler can be linked into chains. One is the target chain, which normally starts with a view object, and continues up the view hierarchy to the window, document, and application. As mentioned before, this chain also handles keystrokes and menu commands. The other chain is known as the co-handler chain. This is a separate chain into which you can install your own TEvtHandler object.

Not every instance of TEvtHandler is given idle time (by calling its DoIdle method). Each instance of TEvtHandler contains the field fIdleFreq, which indicates the minimum interval between calls to DoIdle. If that field is the constant kMaxIdleTime, then MacApp does not give the object any idle time.

Actually, MacApp’s idle processing is a bit more elaborate. The DoIdle method has 1 parameter, which is the idle phase. MacApp defines 3 phases: idleBegin, idleContinue, and idleEnd.

When MacApp starts its idle processing, it calls DoIdle with the idleBegin phase. It then calls DoIdle with the idleContinue phase, subject to the value of the fIdleFreq field. When idle processing completes (i.e., the next user event is available) MacApp calls DoIdle with the idleEnd phase.

In order to use this idle mechanism, you need to implement your background task so that it can do a small amount of processing each time DoIdle is called. Since the idle processing is done by an object, you can maintain state between calls in the state of the object.


Error handling is a very important application feature. In designing the error handling framework for MacApp we wanted to provide an easy way for programmers to catch and recover from errors, and a clear way of reporting errors to the user.

To help catch and recover from errors, we implemented an exception handling mechanism in MacApp. MacApp maintains a stack of exception handling routines. You push a handle on the stack with a call to CatchFailures, passing a handler procedure, and a FailInfo record.

The record is initialized by MacApp with information necessary to call the handler (e.g., current stack pointer, a link to the next handler record). The handler procedure is declared with two parameters: a standard Macintosh error code, and a 4-byte message. The message is used to describe what operation failed, and the error code gives the reason for the failure. Normally the handler is a nested procedure in Pascal so that it has access to the local variables of the enclosing procedure.

There are two ways to pop a handler off the stack. The first is by calling Success. Success just pops the handler off the stack. You must do this before exiting the procedure that established the handler.

The second is by calling Failure. Failure can be called by any routine, not just from within the routine that set up the handler. When you call Failure, MacApp pops the top handler off the stack, restores the registers and other state, and calls the handler with the error code and message passed to Failure. (Note that the process of restoring the registers restores the stack pointer to its original position.)

A failure handler normally does some clean up (e.g., free allocated memory) and returns. MacApp then propagates the failure by calling the next handler on the stack. Eventually, control reaches a handler in the main event loop, which was established by MacApp. This handler displays an alert reporting the error, and the branches to continue handling events.

In order to make things easier for you, MacApp provides a few utility routines. For example, the procedure FailOSErr takes an error code and calls Failure is it is not noErr (0). This makes it easy to write code such as: FailOSErr(FSRead(...)); Similarly, there are utility procedures that check for a NIL return from the Memory Manager, a missing resource, etc.

Catching errors is still your responsibility; MacApp doesn’t try to second-guess what you are trying to do. But if you do use the MacApp failure handling mechanism, then MacApp will automatically put up the appropriate error alerts for you.

MacApp error messages have the general form:

Could not <operation> because <reason>.  <Recovery>

The alert has 3 blanks that MacApp fills in based on the error and message values passed through the failure handlers. In the simplest case, the error code is looked up in 2 tables to produce an explanation of the error and a way of recovering from it. The message code is looked up in another table to produce a description of the operation that failed.

An example of a filled-in alert might be:

Could not save “test doc” because the file is locked.  Use the “Get Info” 
command in the Finder to unlock the file.

The alert occurs if the user tries to save to a locked file. MacApp automatically generates this alert (including substituting the name of the document), provided you test for File Manager errors in your saving code.

If you look at all the possible Macintosh error codes, you will see that there are only a handful of errors that can be meaningfully reported to users. Also, many error codes can be described with the same message.

MacApp uses an ‘errs’ resource to map between an error code and an index into a list of strings. The resource consists of a list of entries, each of which contains an error code range, and the appropriate string index. (Special entries in the errs resource indicate the resource ID of the string list.)

There are a couple of variations on the basic error reporting mechanism. For example, if the failure occurs while processing a command, MacApp will use the command number of the command to retrieve the command name from the menu, and display an alert such as:

Could not complete the “Copy” command because there is not enough memory.

The failure handling mechanism also comes in handy for other things besides errors. For example, when the user closes a document that has been changed, MacApp puts up the standard “Save Changes...” alert. If the user clicks Cancel, the program should abort closing the document.

MacApp handles this case by signaling a failure if the user clicks Cancel. In this case, the error code passed is noErr. In the main event loop, this error code is handled specially, and MacApp does not display an alert. The end result is that the action is cleanly canceled, without the intermediate procedures having to handle this case explicitly.


At the start of this series, Joe Terry asked a couple of questions, that I can now answer.

• How does MacApp make programming the Macintosh easier?

There are a number of ways that MacApp helps Macintosh programmers. First, it handles the common features that every application must have (menus, windows, scrolling, printing, etc.). This means that there is less code for you to write, which leaves more time for you to write application-specific code (e.g., new features).

Consequently, there is no need for you to understand all of Inside Macintosh, before you can start writing your application. Even though MacApp itself is large, you don’t need to understand very much of it before you can get something up and running. Spending a month learning about MacApp is a much better time investment than spending a month learning the Macintosh Toolbox. At the end of that time, your MacApp application will support scrolling, printing, Undo, etc.

MacApp is also beneficial even after you have learned its basics. MacApp provides a well-tested framework into which you add your application-specific code. This makes your application much easier to extend later. You will also end up building your own class libraries, which will make the second and later MacApp programs that much easier to produce.

Finally, MacApp encapsulates many programmer-years of Macintosh programming experience. Apple has been working on MacApp since 1985, and programmers who use MacApp gain the experience and testing that went into it.

• What are some of the design decisions that are easily reversed and some that are not so easily reversed?

Most of MacApp’s design decisions are easily reversed because MacApp is provided in source form and is linked with each application. Changes to MacApp don’t affect existing applications, unless they are recompiled. Of course, existing applications don’t get the benefit of any new features or bug fixes. (This is different from the Macintosh ROM, which is shared by all applications.)

In the past, developers using MacApp have favored improving it even at the expense of changing the programming interface. For example, MacApp 2.0 completely changed the view model, compared to MacApp 1.0. Developers had to spend some time upgrading from 1.x to 2.0, but they were not forced to do so until it was convenient.

MacApp 3.0 is changing the way documents and disk files are handled to make this area more general. Previously, TDocument combined the storage for a document with its I/O aspects; these functions are being separated.

MacApp 3.0 will also provide support for System 7 features (AppleEvents, Edition Manager, etc.). Although I haven’t looked at these MacApp changes, I’m certain that developing applications that support System 7 will be much easier if you’re using MacApp.

• What kind of applications is MacApp “best” for?

MacApp is intended for writing commercial quality applications. It isn’t intended for DAs or standalone code resources. Those kinds of programs could take advantage of an object-oriented framework, but such a framework would be different from an application framework (i.e. MacApp).

So far, MacApp has proven to be suitable for a variety of applications. There are MacApp applications already shipping that deal with 32-bit color graphics, text processing, sound & multimedia, and programming. MacApp was oriented more towards full applications, as opposed to small utilities. You can still write small utilities, but you won’t benefit as much from MacApp’s standard features.


Joseph S. Terry, Jr.

Ajalon Corporation



In TCL the concept of a “chain of command” is really a way of reducing the message passing overhead you would experience in a free form approach to message resolution. Rather than ask every object if a message applies to them, TCL has a specific line of objects that can respond to “direct commands”. At the head of the line is an object called the gopher. The gopher is actually a global variable called “gGopher” with a reference to the object that should be first in line to receive direct commands. The programmer is responsible for setting the global variable gGopher when you want a particular object to be at the head of the line such as a TextEdit field in a database application. When the user hits tab then you would make the next edit field in line the gopher.

Figure 1. Be a gGopher

Also you should note that the supervisor of the Pane that is the current gopher is likely to be the Document that is responsible for the window, rather than its immediate superpane, that the Pane in question is contained in.

Objects in the chain of command are decedents of the CBureaucrat class. This provides a common command handling behavior that all objects in line understand. Every CBureaucrat has a supervisor. If an object cannot handle or doesn’t understand a message then that message is passed on to it’s supervisor. CBureaucrat actually has an instance variable named “itsSupervisor”. This variable is initialized by the default initialization routine, as long as you provide an object as the supervisor.

To implement Undo-able actions you’ll want to use the class CTask. It is designed specifically to for this purpose. Undo-ing on the Macintosh is a central difference in the user interface approach from previous icon/pointer driven environments. But many people quickly realized that you only have one shot, that undo although wonderful was one level deep. If you did anything else after your mistake you could no longer undo the “bad” thing. The explanation of CTask in the TCL manual is short but complete. Remember to a subclass of CTask and store your own instance variables that will contain enough information to undo the action.

If its text changes that your undo-ing undoes then save the whole text. Trying to figure out what piece of localized text you’re undo-ing changes to, at undo time, is rather a ridiculous waste of brain power, use memory instead.

The really exciting news is that there is no excuse for a program written in TCL to not have much more sophisticated undo/redo scenarios. Here is where the class library begins to synergize solutions for us. With CTask and CList, I can build an unlimited undo for a simple action such as the font example in the manual in a page of code. Yes, unlimited undo/redo! I say a page when it could probably be done in a half a page if I didn’t include comments.

And the whole thing would make more sense if I had multiple inheritance at my disposal. That’s another article. What I would do is override the CDocument class Notify() method. What it does now is maintain the lastTask in an instance variable named “lastTask”. And on entry if there is a lastTask already then that is simply disposed of. I would continue to add any undo/redo task onto the current document task list in entry order and allow the user to set a limit on how many of these are kept around. As a new task entered the queue the oldest would be disposed of if the queue were filled.

If you did an example of undo-able programming try CMouseTask. Its not very clear from the manual so print out the source code and read it carefully. You’ll see that there are no instance variables defined in the “.h” portion of the source and the “.c” source includes only empty methods. This is the proverbial exercise for the reader. Look at the code for a mouseTask in Gregory H. Dow’s (GHD) CPaintTask.c in the project Art Class. This is very nicely done. It’s not optimal in speed of execution, but remember that in programming the “meta machine” of a class library it is more important to make “efficient” use of the the class library.


In MacApp there is a concept called the target. The target is the object instance upon which some command will act.1 In, TCL there is the gGopher. Further, there are three conceptual “target chains” which are the paths along which message with travel in search of a handler. There is the command chain, the click chain, and the cohandler chain. These are roughly equivalent to the “chain of command” and “visual hierarchy” concepts in TCL.

Note the similarity between handling a mouse click and menu command between MacApp and TCL. Since a mouse click involves a position in the window, it is handled by going down the view hierarchy in MacApp. Similarly, in TCL a mouse click in a particular position in a window goes first down the visual hierarchy DeskTop->Window->SubView->SubView->TargetSubView. A menu selection has no positional information and is handled by starting at the target/gopher and working upward from SubView->SubView->Document->Application. Most menu commands are normally handled in the Application Object. The only “classical” exceptions are the Apple, File, Font, Size and Edit menus which have some default behavior built-in.

Architecturally speaking, menus are a very, very old user interface concept and I expect some young bucks to come up with new more powerful and more ... human oriented, ways of making choices. Menus have proven useful, but as applications become more complex and the range of choices become larger, in my opinion, user interface designers are failing to create intuitive menu selection arrangements and it may not be their lack of talent or creativity, but a fundamental limitation in the conceptual framework or “design school” they are working from. For instance in the January 1991 MacTutor there is an article about Pie Menus by Boyd and Andrea Hays of Boulder, CO. This is the kind of article we all need to see more. This piece is based on an article called “An Empirical Comparison of Pie vs. Linear Menus”, by J. Callahan, D. Hopkins, M. Weiser, and B. Shneiderman[sic], in the ACM’s SIGCHI 1988 Conference Proceedings. The general conclusion of the ACM paper was that users could select items from pie menus, in certain instances, faster than from linear menus.

Figure 2. Pie Menu

It is commonly known in the clinical psychology literature that we humans are able to juggle about 7 to 12 conceptual frameworks, items, numbers, letters, etc. at the same time. That’s it. Creating a menu with 20 or thirty choices and further depth in hierarchical menus seems ludicrous if your aim is ease of use AND recall.

I would like to see a limit place on the items in menus. After that you must move to a different “platform”/Dialog Box/”Choicer” to see other choices. Now this does smell of the old nemesis “mode”. As a theoretical user interface component “mode” has been taking a bad rap for over twenty years. There was even a T-Shirt (I love T-Shirts) that had the slogan “Don’t Mode Me In”. Cute ..., but the concept of “context” is terribly important to the fast recognition in the normal operation of the human mind. Call it mode or context or frame of reference, but, if you present too many choices too far apart in space, it is very difficult to achieve a “state of fluidity” with the software that approaches what is possible with the incredible user interface of a paint brush in the hand of a Picasso or Da Vinci. That is the ultimate user interface of any tool for the hand of man.( Ok, maybe a piano in the hands of a Tchaikovsky, or a blues song in the throat of a Holiday or James).

Don’t think these issues don’t apply to your CURRENT project. They do ... even if you don’t realize it.


This is a very technical subject and I hope that the highlights and gloss over job I do here will not offend those who know more that than I do or those that expect this to be the definitive “How to avoid ID -25 in ten easy lessons”. Let’s concentrate on using our “machine” efficiently. It’s rather simple. When you initialize an Application object it requires three parameters. All three are related to low memory conditions. The first one is the extraMasters number. This number determines how many Master Pointer Blocks you want for your application to run. Each Block usually contains 64 master pointers and this is the number of relocatable handles that your application can create WITHOUT creating another Master Pointer Block.

The key is this after “observing your heap zone’s behavior” you determine that you only need 5 Master Pointer Blocks throughout a run of your program. Then it is much better for you to call MoreMasters or in this case send five (5) as the extraMasters value when initializing an Application object. That way the memory manager will not create them whenever it needs them, possibly fragmenting your heap very badly. This is the first and most important Macintosh memory management technique. When the memory manager allocates a Master Pointer Block it just locates free memory and plops one down there ... locked in place forever. The new memory manager is getting smarter, but their are a few bugs...

That phrase “observing your heap zone’s behavior” describes something you can do with MacsBug or TMON. Basically, you can look for the number of non-relocatable blocks that are 264 bytes long (64 pointers times 4 bytes each plus an 8 bytes for the block header). Add 5 and use that number to initialize your Application objects.

The next parameters are the “aRainyDayFund” and the “aCreditLimit”. The description in the manual is adequate (page 230). These are different than extraMasters because extraMasters is a direct Mac ToolBox issue. These parameters require that we again use the “machine/class library” the way it was intended. There is a special logic that must be followed. Let’s say that you allocate 50K for the rainy day fund and set your credit limit at 10K. This means that when the Mac memory manager cannot fill a memory request then the “GrowMemory()” message is sent to the Application object by way of the “GrowZoneFunc” in the CError Class. Actually, the global variable “gApplication” is sent the message. You MIGHT have someone, an object, in gApplication that responded to this message and passed all other messages to the ACTUAL application, but what a hack... The default GrowMemory message handlers in the Application object will first ask if there are temporary buffers that can be eliminated by sending itself the message “MemoryShortage()”. If that doesn’t work then the object performs thusly:

ADoes the Rainy Day fund still exist?

 1 If yes, then can I borrow from rainy day (Is “loanApproved” true?)
 is what I’m asking for within my “creditLimit” (loanApproved can be 
false in that case)
   A  if yes, then proceed to determine if my request will leave me with 
a MINIMUM_BALANCE. MINIMUM_BALANCE is a constant with a normal value 
of 2048 bytes.

 1 if yes, then give us everything NOT just the requested amount. Holding 
the minimum in reserve.

 2 if no, then can I satisfy the request and leave NO reserve.

    A If yes, then do it you fool. Liquidate the fund. Cash in the chips, 
etc. The user is so innocently unaware.(he he he)

    B If no, then Do (A) and hope for the best. Watch Out Below. There’s 
likely to be a crash. Save the Documents and Disk files first.

    B if no, then loanApproved is false and I’m asking for something over 
my credit limit. (Bad boy) So, now I resort to (B) below.

 2 if no, then I do (B) below.

BIf no, rainy day fund is gone then if this request is OK to fail then 
I just return with that information, otherwise I try one last resort 
the message handler “OutOfMemory()”. 

This message handler is more of an bourgeois apologist than a real blue collar proletariat. It flashes some kind of conciliatory message about being out of memory and then waits for another event. What a wimp!

Ok. Whew! Now you know everything you need to know about low memory conditions. If you don’t like what you’ve just read then override it. The whole point of all these games with rainy day fund and credit limit is to establish a “problem domain lexicon” or a set of jargons and objects that you can manipulate and think about as you establish the low memory policies for your application. If you build on and enhance the “reality” of the established lexicon. “Loan Memory to short-lived objects”, “Establish interest on especially hoggy processes” (read - tell the user that this is inadvisable unless they want to burn memory or wait forever). Build on the illusion and you will be able to share your code with your colleagues and talk about concrete things (and charge your enemies obscene interest).


Printing is one of the most complex tasks on the Macintosh and I will provide just an advance on the territory. What TCL provides is a very simple model. Every printer is a Quickdraw device with a border and a margin and dot density. The dot density can be determined along the horizontal or the vertical axis and allows for a measure of proportional control to rest in the application, rather than for instance trusting a printer to print your circle perfectly circularly; you can adjust drawing routines.

In the CPrinter class the access method GetPageInfo provides this information and is the only general routine for interrogation of the state of the “printing engine”. You would only call this routine early in the print cycle or before printing actually began. Calling this routine during printing will confuse the Macintosh printer drivers.

So we start out by having a document that is active that we want to print. When initializing this document we would have indicated if it was “Printable”. If so we would have initialize the instance variable “itsPrinter”, “pageWidth”, and “pageHeight”. Having done this the document is ready to print.

We select the “Print” command from a menu or in some other way indicate that we want to print this document. Normally a direct command “cmdPrint” will then be handled by the DoCommand message handler of a document and will send the message “DoPrint()” to the printer object in the “itsPrinter” instance variable of a document object. Every document can have a different way of responding to the “Print” command by having a different “kind” of object or subclass of CPrinter in its “itsPrinter” instance variable.

DoPrint’s normal behavior is to display the standard PrJobDialog as shown in the figure.

Figure 3. PrJobDialog Imagewriter

If the user click’s OK then DoPrint sends the message PrintPageRange to itself. PrintPageRange is the workhorse that does the actual printing. It opens a print Document (toolbox kind not TCL kind) and sends the message “PrintPageOfDoc” with a page number for every page to be printed. Either 1 or 1 2 3 or 1 2 3 4 5.

Your Document’s PrintPageOfDoc routine must then “draw” on this printer page just as any quickdraw “page/screen”. Actually, it sends, by default a message “PrintPage()” to its main pane. This decouples printing between the Document/Window and the Panes within them.

The PrintPage message handler in CPane is very primitive by itself. It just draws the entire pane using standard quickdraw calls. These calls are bracketed by calls to “PrOpenPage” and “PrClosePage” with the Macintosh PrintPort as the only parameter. This is a toolbox level detail that I don’t want to dive into, but at this stage you would have to override PrintPage in CPane to make many interesting things happen like multi-page printing. To do that you would just have to actually use the parameter pageNum in PrintPage. With that parameter you would interrogate your internal data structures and “draw” the “pageNum” page.

This is not in my opinion an advance in the state of printing abstractions, and I would say that here, in this programming domain, that TCL is the weakest in terms of the available conceptual tools. This does seem to be a weak area in MacApp as well. Data structures and printing. These two areas need more attention from the OP community.


With the advent of Multifinder, it has become more important that an application make active use of the time when it is not directly interacting with the user. Sometimes this is as simple as saying “Hey operating system, here’s some time I don’t need”. Cooperative Multitasking is much like volunteer fire departments. It works in low pressure, low use situations. When applications are “well behaved” and courteous to one another everything is fine. When they are nasty and only execute GetNextEvent, then the whole system is at risk. The solution to this dilemma is known as Preemptive Multitasking. That would not allow an application to “hog” the CPU any longer than necessary, else they would be swapped out and allow someone else to run by force. Couple that with hardware memory protection and you’ve got a real ball game on your hands. I can’t wait.

TCL allows two types of things to be scheduled for regular attention. One type is the “idleChore” these are arranged in a list and perform their function during the time when there are no Macintosh system events directed at the application. (User is thinking, not typing).

The other is the “UrgentChore” which is arranged in a cluster and is performed after every event (even idle’s), if and only if the “urgentsToDo” Application object instance variable is true. After urgents are done then the urgentsToDo variable is set to false.

The default Application “Idle” message handler is the seed of much activity in TCL. First it checks to see if the rainyDayFund is used up. If so, it tries to replenish the fund, and if it is not successful gives the user an unpleasant warning/feeling.

Next it does something that is quite neat. It gives each “Bureaucrat” in the chain of command a chance to do something by sending a “dawdle” message up the chain, starting at the gopher. If you remember your chain of command, this is an very nice time to do perhaps user timers. The Application object gets a “dawdle” message too.

Last but not least, each object in the IdleChore list is asked to “perform”. That is that each object is sent the “perform” message and a parameter which represent the largest signed long integer possible. I don’t know why. Of course the classical use of the idleChore is to flash the cursor in a TextEdit field. The default dawdle for TextEdit is in CEditText.

One last thing about idle chores. Since they are in a CList class data structure they can be ordered in a variety of interesting ways. (By Need?, By Kind?, By Appropriateness?) This is a glimpse of the power of flexible data structures.

Urgent chores are more mysterious. These chores are not arranged in a list (CList) per se. They are arranged in a cluster (CCluster). The difference is very subtle. Urgent chores are done once, and then have to be “scheduled” again by some object. The speed of access may be one explanation for the CList vs. CCluster difference, frankly, I don’t know. One thing is for sure, this is a powerful way of adding things to the “computational sequence” without actually performing the operation yourself.

Any object can in effect say “I want this to be done as soon as it is practicable”. The TCL decides when that time comes and does it. Very Nice. Imagine a lot of calculations you want done but you want the user to be able to continue to select new ones. Build a list and execute them “en masse”? Or just send the message “AssignUrgentChore()” for each calculation to the Application object which is in the global gApplication at all times. Simple.

I really don’t have much else to say on this subject. Architecturally, Urgent chores and Idle chores are extra pipe in the walls for cables you might want to lay in the future. Inter Application Communication (IAC) in System 7.0 should make features of this nature more used and abused. I hope its not a nightmare. Is this parallel processing? Not quite, but the flavor is very interesting on the programming palette.


Error Handling is the last subject we shall cover and the pundits are already saying that error handling should be the FIRST consideration. Well, in the old days, of procedural programming that MAY have been true. In the present day of OP programming error handling, as opposed to logical errors and bad pointers, is rather trivial. One of the advantages of OP is that only certain kinds of errors are possible. Of course we need to remember the strict distinction between the world inside the application, but outside methods/routines/handlers. In this in-between world there is order and orderly progression. This is the “machine” that passes messages and responds to them, broadcasts them and eats them. The world inside methods/routines is the old free for all that we’re quite used to. A stray pointer can bring down the whole party.

The first concept is to separate your error handling schemes for the world inside methods/routines and the world outside. Once that is done you’ll feel better. Next let’s take a look at the CError class. It is three pages in the manual. I won’t repeat those pages here (pages 313, 314, 315). Basically, to really do sophisticated error handling you will have to create a subclass of this class. The functions provided are good solid building blocks.

When the Application object is initialized an instance of CError is created and stored in the global gError. The manual says “you can” create a subclass of CError for more sophisticated error handling and I’m saying “you must” do so.

The only problem here is that the default Application initialization routine takes on so much that at this point (needing sophisticated error handling) you have to replace/override the entire routine. You can’t just do the neat stuff and then call the inherited method. Why? Because it then proceeds to fill GLOBAL variables with stuff, like gError.

I don’t know what the solution is here, but this ain’t it. Again separate your error handling for the two worlds and you will find very few errors in the final product can possibly slip through.


When you read “and XYZ sends a ‘message’ to JKL” you may say to yourself “Why use all this fancy language, when its plain that one “function” calls another “function”. Well, the answer is more shadow than substance at the moment. Even for those that claim great successes with OP, these are largely research projects or projects that are under similar kinds of performance pressures. The pressures of the “real” world, business and defense programming are slowly using many of these techniques, but most organizations are still just at the talking stage.

Also the technology is somewhat limiting. OP without multiple inheritance (MI) which neither MacApp or TCL have (They have Single Inheritance (SI) just as Smalltalk does) is not unanimously considered the most complete model for OP. Larry feels differently, and I acknowledge that there is nothing you can accomplish with MI that you cannot accomplish with SI. A similar argument can be made for assembly language vs. C or Pascal.

In fairness, Larry can be ever so persuasive in person and in writings. The real story is unfolding here in your hands. YOU ... yes YOU ... All of those who read this article are now right-smack-dab in the middle of what I believe to be one of the great historical times in the saga of “artificial computation”. Read everything you can get your hands on and hold on ... It’s the Century of OP.

The summary is really a moral.

Use what you got.

Learn the class library of your choice. Learn how to change and improve the behavior from within the design framework. If you seriously disagree with the structures or arrangement of MacApp or TCL ... AND you try to do something about it; you will quickly find yourself on the BLEEDING edge and looking for a high slippery ledge. Another way of saying this is, if you don’t get the “program”, class library concept, don’t attempt to use it.

Too much overriding is hazardous to the health of your programs.

Another thing ... If you are developing classes that are generally useful in MacApp or TCL and you don’t release them to the public, either for a fee or gratis, you will be hunted down and fed to the great blue programming dragon. The age of OP is one of giving, sharing and building on Other Peoples Work (OPW). Just do it.

It will come back to you a hundred fold. I know this sounds ... well sappy ... but it does work. Let’s all stop working so hard ... OK??? Where are those entrepreneurs who steal ... I mean “merchandise” honest programmer’s work and sell it for “Distribution Charges”. Why don’t we have a “Reusable Code CD-ROM”? $59.00 Cash or Visa/MC. Source code is better than an application any day of the week.

Count those cycles ... I mean messages.


1 Introduction to MacApp 2.0 and Object-oriented programming, Apple Computer, Inc.


Community Search:
MacTech Search:

Software Updates via MacUpdate

Tidy Up 5.3.7 - Find duplicate files and...
Tidy Up is a full-featured duplicate finder and disk-tidiness utility. Features: Supports Lightroom: it is now possible to search and collect duplicates directly in the Lightroom library. Multiple... Read more
Pinegrow 5.97 - Mockup and design web pa...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
BlueStacks 4.210.0 - Run Android applica...
BlueStacks App Player lets you run your Android apps fast and fullscreen on your Mac. Feature comparison chart How to install Bluestacks on your Mac Go to MacUpdate and click the green "Download"... Read more
WhatsApp 2.2027.10 - Desktop client for...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Art Text 4.0.1 - $29.99
Art Text is graphic design software specifically tuned for lettering, typography, text mockups and various artistic text effects. Supplied with a great variety of ready to use styles and materials,... Read more
Adobe Dreamweaver CC 2020 20.2 - Build w...
Dreamweaver CC 2020 is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Dreamweaver customer). Adobe Dreamweaver CC 2020 allows you to... Read more
Adobe Acrobat DC 20.009.20074 - Powerful...
Acrobat DC is available only as a part of Adobe Creative Cloud, and can only be installed and/or updated through Adobe's Creative Cloud app. Adobe Acrobat DC with Adobe Document Cloud services is... Read more
beaTunes 5.2.10 - Organize your music co...
beaTunes is a full-featured music player and organizational tool for music collections. How well organized is your music library? Are your artists always spelled the same way? Any R.E.M. vs REM?... Read more
DiskCatalogMaker 8.1.5 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Meteorologist 3.4.1 - Popular weather ap...
Meteorologist is a simple interface to weather provided by It provides the ability to show the weather in the main menu bar, displaying more detail in a pop-up menu, whose contents are... Read more

Latest Forum Discussions

See All

Steam Link Spotlight - Disco Elysium
Steam Link Spotlight is a feature where we look at PC games that play exceptionally well using the Steam Link app. Our last entry was Signs of the Sojourner Read about how it plays using Steam Link over here. | Read more »
Distract Yourself With These Great Mobil...
There’s a lot going on right now, and I don’t really feel like trying to write some kind of pithy intro for it. All I’ll say is lots of people have been coming together and helping each other in small ways, and I’m choosing to focus on that as I... | Read more »
Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »
The King of Fighters Allstar's late...
The King of Fighters ALLSTAR, Netmarble's popular action RPG, has once again been updated with a plethora of new content. This includes battle cards, events and 21 new fighters, which increases the already sizeable roster even more. [Read more] | Read more »

Price Scanner via

Clearance 2019 13″ 2.4GHz/256GB MacBook Pro o...
B&H Photo has dropped their price on the clearance 2019 13″ 2.4GHz/256GB Quad-Core Silver MacBook Pro by $500 off Apple’s original MSRP to a new low of only $1299. Expedited shipping is free to... Read more
$219 Apple AirPods Pro are back at Verizon, s...
Verizon has Apple AirPods Pro on sale again for a limited time for $219.99 on their online store. Their price is $30 off Apple’s MSRP, and it’s the lowest price we’ve seen for AirPods Pro. Available... Read more
Apple’s $779 13″ MacBook Air deal returns to...
Apple has clearance, Certified Refurbished, 2019 13″ MacBook Airs available again starting at $779. Each MacBook features a new outer case, comes with a standard Apple one-year warranty, and is... Read more
$200 13″ MacBook Pro discounts are back at Am...
Amazon has 2020 13″ 2.0GHz MacBook Pros on sale again today for $150-$200 off Apple’s MSRP. Shipping is free. Be sure to purchase the MacBook Pro from Amazon, rather than a third-party seller, and... Read more
Deal Alert! Apple AirPods with Wireless Charg...
Sams Club has Apple AirPods with Wireless Charging Case on sale on their online store for only $149.98 from July 6, 2020 to July 9, 2020. Their price is $50 off Apple’s MSRP, and it’s the lowest... Read more
Xfinity Mobile promo: Apple iPhone XS models...
Take $300 off the purchase of any Apple iPhone XS model at Xfinity Mobile while supplies last. Service plan required: – 64GB iPhone XS: $599.99 save $300 – 256GB iPhone XS: $749.99 save $300 – 512GB... Read more
New July 2020 promo at US Cellular: Switch an...
US Cellular has introduced a new July 2020 deal offering free 64GB Apple iPhone 11 smartphones to customers opening a new line of service. No trade-in required, and discounts are applied via monthly... Read more
Apple offers up to $400 Education discount on...
Apple has launched their Back to School promotion for 2020. They will include one free pair Apple AirPods (with charging case) with the purchase of a MacBook Air, MacBook Pro, iMac, or iMac Pro (Mac... Read more
July 4th Sale: Woot offers wide range of Macs...
Amazon-owned Woot is blowing out a wide range of Apple Macs and iPads for July 4th staring at $279 and ranging up to just over $1000. Models vary from older iPads and 11″ MacBook Airs to some newer... Read more
Apple Pro Display XDR with Nano-Texture Glass...
Abt Electronics has Apple’s new 32″ Pro Display XDR model with the nano-texture glass in stock and on sale today for up to $144 off MSRP. Shipping is free: – Pro Display XDR (nano-texture glass): $... Read more

Jobs Board

Physical Therapist Assistant - *Apple* Hill...
Physical Therapist Assistant - Apple Hill Rehab - Full Time Tracking Code 62519 Job Description General Summary: Under the direct supervision of a licensed Physical Read more
Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
*Apple* Mac Product Engineer - Barclays (Uni...
Apple Mac EngineerWhippany, NJ Support the development and delivery of solutions, products, and capabilities into the Barclays environment working across technical Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.