TweetFollow Us on Twitter

PowerPlant Tips

Volume Number: 15 (1999)
Issue Number: 4
Column Tag: PowerPlant Workshop

PowerPlant Tips, Tricks, and Gotchas

by John C. Daub, Austin, Texas USA

Tidbits of knowledge to improve your use of PowerPlant

Hello, Again

I hope you've been enjoying my "series" of articles on PowerPlant as they've appeared here in MacTech Magazine. I've enjoyed writing it. Just about a week before I started writing this article, one of the hard drives on my Mac at home starting making a strange clicking noise, so I've disabled it - there went my development drive. So since I don't have all my normal resources at my immediate disposal, I thought this month I'd turn to the Internet for some input and posted a question to the comp.sys.mac.oop.powerplant newsgroup. I asked the readers to post their favorite PowerPlant "tip, trick, or gotcha". I received a few, but one reader had a lot to say. I've dedicated a special section of this article to his experiences :-)

This is the sort of stuff that you learn through experience. As much as Carl tries to document PowerPlant, most of these things you just don't appreciate until you get bitten, and especially if they save your hide or find that niggling bug that you haven't been able to squash for the past three months. This isn't to say I'm the most experienced programmer out there, but rather to try to put some of those experiences of mine and your fellow PowerPlant-users down in print to document them. A magazine article's a good medium for this purpose. So I tried to collect from various peoples and sources and put down what's relevant today. Some of this might still be relevant years from now, others obsolete, or maybe all of this moot.

But still, I remember what it was like when I started. It's a steep learning curve to get into programming, and definitely into PowerPlant. Once you're there it's not always easy, but it's certainly not as difficult as when you started. Hang in there. I remember all of the wonderful people that helped me when I was starting (Marco, Dan, Tim, Eric, Greg) and still help me today (especially you, Greg) and so I'm just trying my best to return the favor. It's this really cool Mac developers community that we have full of openness and helpfulness. Maybe that's why Mac folk seem to find linux-ppc really cool (and can't wait for OS X). And that's why I love to stick with Mac. If we can keep this kind of community of sharing going on, that'll benefit us in the long run.

So read on. I hope you'll learn something new. I know that I did.


Let's start out with some general tips for using PowerPlant. These should remain valid for a while as they are more principles of PowerPlant's design and implementation style than matters of code. After Tips will come the Tricks, and following that the Gotchas. The numbers are present for ease of reference. I present these in no particular ordering, except for this first one:

1. Always read the release notes (or, RTFM)

This cannot be stressed enough. PowerPlant is a very dynamic framework that is ever-evolving to suit the needs of Mac OS software developers. It's certainly frustrating at times to have to keep up with each release, but you must. Reading the release notes is the shortcut to seeing what changed and learning how to quickly update your project to suit.

There are sections in the release notes that deal with new features, a detailed change log, possible referrals to documents and PowerPlant TechNotes (yes, we have them too). And most importantly, we try to catch all of the places where existing projects will have to tweak something and report those first in the notes file. Heed them and it should eliminate most of your upgrading pains and posting to the newsgroups (or emailing Metrowerks Support). You'll get faster turnaround if you RTFM first.

And if you do have trouble, of course email Metrowerks Support at <> and/or post to the comp.sys.mac.oop.powerplant newsgroup. There's usually someone just a keyboard away that can help.

2. Check the Reference CD

On your Reference CD in the PowerPlant Examples folder we keep a great deal of information about PowerPlant. Not only examples, but also archives of obsolete code, TechNotes, and archived release notes. Yes, all PowerPlant release notes archived back to DR/1. Eases those upgrades when you jump a couple releases.

PP TechNotes is our folder of PowerPlant Technical Notes (just like Apple's TechNotes). This is a good place to go for explanation on greater concepts like the design of the Appearance Classes, or understanding the Networking and Internet Classes, docs for Andy Dent's More Table Classes, and many other items of interest. Worth checking out.

3. Keep up with OS evolution

Although PowerPlant is written in C++ and is an application framework (see my "What is PowerPlant?" article , December, 1998 MacTech), it remains very close to the Toolbox. A lot of people are after higher levels of abstraction and encapsulation these days, mostly because it aids porting to other platforms. PowerPlant doesn't want to prevent you from going cross-platform, but it'd rather focus on the Mac. Do one thing really well instead of trying to do more and failing.

And so PowerPlant must keep pace with the Mac OS as it evolves. ATSUI, Carbon, OS X, OpenGL. There are some great things in store for the future of Mac. PowerPlant will be there, we all have to keep up.

4. This is C++. Take advantage of what the language has to offer

As the C++ language has evolved and compilers race to implement the standard, PowerPlant has made more and more use of the C++ language. By the time you read this, CodeWarrior Professional 5 should have shipped and hopefully you have a copy on your desk. PowerPlant now uses a real exception class, LException, publicly inheriting from std::exception as the means of providing information about error conditions (instead of the ExceptionCode, which is just a typedef'd long). Templates are being used more (TArray, I'm working on a template version of UMemoryMgr for post-Pro 5). RTTI is utilized throughout the framework. C++ is a good language - strive to take advantage of it.

So as well, use classes like TArray to manage your lists of data; use LString and friends LStr255, LStringRef, and TString (see my article on LString in the January, 1999 issue of MacTech). Be typesafe. Learn how great stack-based classes are for resource management and exception safety. Work logically.

5. Use compiler warnings

Compiler warnings are there to help you. They are not errors, which mean something is certainly wrong, but rather they are warnings - informative messages to try to point out potential problems. Turn them on, use them on your code. They can prevent problems.

Figure 1. CW Pro 4 C/C++ Warnings Preference Panel.

As you can see in Figure 1, there is a good deal of coverage performed by the Metrowerks C/C++ compiler. I'd like to talk about three warnings: Implicit Arithmetic Conversions, Non-Inlined Functions, and Hidden Virtual Functions.

Implicit Arithmetic Conversions is a warning issued "if the destination of an operation isn't large enough to hold all possible results. For example, assigning a value of a variable of type long to a variable of type char will result in a warning if this option is on" (Metrowerks 1998, CCR-26). PowerPlant strives to compile cleanly with this warning on, but some areas do slip through (e.g. Grayscale Implementations of the Appearance Classes). Barring that one point, PowerPlant should compile cleanly with this option.

Non-Inlined Functions is a warning that provides you with information on what you asked the compiler to inline but it did not for some reason (remember, inline is just a suggestion). Aside from the usual guidelines for inlining, the inline depth, a C/C++ compiler setting, does affect the output of this warning. Depending upon your inline setting, you may receive these warnings on PowerPlant code. Play around with the inline levels and see how that affects your resulting binary. Choose what works for you. Generally I leave this option off and just use it when I wish to fine-tune my inline settings for maximum gain from this C++ language feature.

Hidden Virtual Functions is another warning with which PowerPlant should compile cleanly. PowerPlant does compile cleanly with this warning enabled, but not without a little help from a #pragma. TArray hides some inherited virtual functions, but due to the design and intent of the class we can guarantee this hiding is safe; in fact it is needed for the intent of the class. But when you use a TArray, you receive several hidden virtual function warnings. To quiet the compiler perform an explicit instantiation of the template or just at the point of instantiation, wrap it with #pragma warn_hidevirtual off/reset like this:

   #pragma warn_hidevirtual off
         template class TArray<FooData*>;
   #pragma warn_hidevirtual reset

Using a technique like this you are able to ensure quiet and clean compiles with TArray. Look in the PowerPlant sources - this technique is used throughout the framework.

All compiler warnings are useful and generally I leave all on except the non-inline and arithmetic conversions warnings, turning those on as needed. Refer to the C Compilers Reference on your CodeWarrior Reference CD for more information on the warnings and other language preferences.

6. Explore unfamiliar areas of PowerPlant

I do not know all of PowerPlant, but I do my best to at least have a familiarity with all of PowerPlant. It takes time to learn and master every aspect, and with PowerPlant so large it's difficult to know it all. But if you are at least familiar with what PowerPlant has to offer then in the future when you have a new project, by knowing what PowerPlant has to offer you can determine if it's the right tool for your new job. Or at least you can avoid reinventing the wheel. I've seen a lot of people spend hours writing something only later to find that PowerPlant already had something better.

For example, do you know what LSharable is? Have you tried using the AppleScripting support? What about the Networking and Internet Classes? Thread Classes? Debugging Classes? Keep exploring PowerPlant. It has a lot to offer.

6a. Check the Contributed Class Archives

Located off Metrowerks' website you will find the PowerPlant Contributed Class Archives, sometimes called the "contrib archives", or some similar abbreviation. This is an archive of PowerPlant classes submitted by your fellow PowerPlant users for your use. The story usually goes that someone had a problem they needed solved, they couldn't find an existing answer so they invented their own. The Warrior believed their situation wasn't a unique experience, so they submitted their code to the archives for public distribution. You can find a lot of great stuff on there.

Some of the code is old, might be out of date, might not even work. Metrowerks can do nothing about this. All Metrowerks can and does do is provide the web and ftp space, and the search engine. Metrowerks cannot vouch for the code on the archive, cannot support, cannot fix, etc. that code. For any issues with items on the contrib archive, you will need to contact the author of the code for support.

And now to speak a bit more on a code level....

7. Never assume the drawing state. Before you perform any operation that draws, always set the drawing state exactly as you need it.

That could be as simple as ensuring FocusDraw() is called (and don't forget that FocusDraw() returns a Boolean if it succeeded in focusing or not - check it), or it might require you to load text traits, ApplyForeAndBackColors, or a host of other things. The key to remember is to never assume the drawing state and always establish it as you need.

One common "rule" has been to save the current state, set it as you need, then restore the original state. Usually this was done because too many assumptions were being made, be it that the state wouldn't change or that nothing else could change the state or people just want to be paranoid and safe. If however you base upon the premise that everything must set their state before they draw, then the save and restore becomes unnecessary as there are no assumptions being made. To then save and restore adds extra overhead and bloat you just don't need.

Of course there are times where you must save and restore, and sometimes this rule has to bend a bit, but those are exceptions and not the rule.

8. Always check return codes

Exceptions are a wonderful part of C++, but the Toolbox doesn't throw exceptions; instead it returns error codes. Sometimes the error codes are a return code (FSWrite), sometimes returned as a parameter (TempNewHandle), sometimes indirectly (NewHandle, returns nil on failure), sometimes signaling to look elsewhere (NewHandle returning a nil Handle tells you to call MemError), sometimes in other places (ResError). But no matter where or how you obtain the error checking, always perform it and handle it as you can. If you can handle and recover, then do so. If you cannot, do what you can, perform any cleanup, and report that error (typically throwing an exception, e.g. ThrowIfOSErr_()).

If you don't check return codes and don't put a mechanism in place to handle those situations, then don't be surprised when you cannot explain the strange new behavior your application has now taken on.


9. Option-click to use the color picker in Constructor

The color popup button/menu that you see in Constructor editors such as the Text Traits editor (to edit the color of the 'Txtr') or the LWindow Property Inspector (to edit the 'wctb' resource) normally pops up a menu/palette of colors to choose from. However, if you find using the Color Picker more to your needs, option-click on the button and the Color Picker will appear.

10. Use drag and drop to create instances of widgets not within Views in Constructor

When you create a 'PPob' resource, typically you create a container View (LView, LWindow, LDialogBox, etc.) and place other widgets inside of the container. But what if you want to create a single instance of a widget, like a single LPushButton; perhaps to use as a "template" for some widgets you need to create on the fly. Simple. Drag an instance of the widget from the Catalog window into Constructor's Project Window (not to be confused with the IDE's project window). That will create a 'PPob' resource containing nothing but that particular widget. No container view. Totally independent. You can establish its properties like you normally do in Constructor (double-click, open Resource in the Layout Editor, double-click on what you see to open the Property Inspector window for the widget). To instantiate the widget at run time, use UReanimator::ReadObjects().

11. Use Constructor's hidden preferences

Did you notice that Constructor has no Preferences dialog? Constructor does have a Preferences file and it does have preferences, but no user-accessible means of manipulating those preferences. And with Constructor currently in maintenance mode, it's difficult to justify the effort required to add a Preference dialog. But that doesn't mean there aren't preferences that you can modify - you just have to know where to look.

Open a copy of the Constructor application in your favorite resource editor (I prefer Resorcerer). Look for the 'INSP' Resource. The contents of this Resource (all one byte of it) control the "pinned" state of the Property Inspector window. If the byte of this Resource is zero, there is only one Property Inspector window shared by all objects (of course you can pin individual instances of the window by clicking the "pin" icon). If this byte is a non-zero value, then all Property Inspector windows open "pinned". If you find yourself pinning the Property Inspector window a great deal, you may want to consider turning this byte on to ease your mouse-clicking finger.

Another hidden preference lies in 'STR#' 1099, index 4. The Constructor application ships with this string as "AM". In this mode, Constructor will attempt to use Appearance Implementations when rendering widgets in the Layout Editor (some widgets are hard-coded to use Grayscale Implementations due to Resource Manager limitations). If you change this string to "GA", Grayscale Implementations will be forced in the Layout Editor.

12. Mark your Resources as purgeable

When you access a Resource, the Mac OS Resource Manager first looks to see if that Resource is already in memory. If so, it returns a Handle to that existing instance of the Resource, else it loads a copy from disk. This is a wonderful way of reducing memory footprint as everyone shares a single instance of the Resource data. But what if you wish to have multiple instances of a particular picture in a window, and this picture comes from 'PICT' resource? If they all share the PICT data, if when a window closes it calls ReleaseResource upon its cached PicHandle, the next time the other window needs to redraw and accesses that now-released Resource via its now-stale PicHandle? You'll probably crash. It's not good to pull the rug out from under someone.

So instead, you could DetachResource, but that wastes memory by having multiple instances of the same (and typically read-only) data. Still, it's a way to go. Or, just never assume you have a valid Handle (as someone may pull the rug out from under you) - just GetResource every time you need it and cannot be certain of the Handle state. Then to follow through, never call ReleaseResource on that Handle; instead mark your Resource as purgeable and let the Memory Manager handle releasing it for you. Why release it before you need it? Your app will feel a lot slower if it has to load Resources from disk every time it needs them, so why not let them be cached in memory? Just remove them if you need it, and ensure they are always there when you need them. Again, never assume, always make the state known and certain.

PowerPlant works to practice this in all possible places, like handling 'Txtr' Resources (UTextTraits) and 'PICT' Resources (LPicture::DrawSelf()). Other Resources include: 'STR ', 'STR#', 'ICON', 'icl8' and other icon Resources, etc. It might make reports from tools like Spotlight a little noisy, but that's ok. I consider it a bug in Spotlight ;-)

13. Use the PowerPlant Resources folder

A lot of people do not realize that we do provide the necessary Resources for working in PowerPlant. In fact we do, and they are within the PowerPlant Resources folder. Here you will find all of the necessary resource files you need, like PP Action Strings.rsrc, PP AppleEvents.rsrc, and a host of other files needed for PowerPlant to work correctly. Then also some ones needed to get certain features to work: GetDirectory.rsrc, EmptyMenu.rsrc, CustomTextColorCDEF.rsrc. Finally, some utility files like Resorcerer and ResEdit TMPL (template) files, and PowerPlant.r for you Rez-lovers out there.

13a. Use Rez/DeRez for localization

Use the above PowerPlant.r file and Rez/DeRez your .ppob files to help you localize your PPob's. The IDE does support both Rez and DeRez.

14. The class browser is your friend

Learn what the Class Browser is and learn to love it. It's really great at helping you navigate code. I find it's a useful reference tool (what better way to know what a function or class does than to read source!). I also find looking up information in my project much easier (that Catalog window is wonderful). Class browsing is more effective for C++ (and other OO languages) because it lets you see the natural structure of the class, including what was inherited, overridden, overloaded, etc. Source alone sometimes cannot give you the full picture.

Also, to make life browsing (and debugging, and just in development overall), don't use precompiled header files (.pch, .pch++, etc.). I've found them to be evil. You're welcome to use them if you'd like, but I've found that a good prefix file is all you really need and quite less headache in the long run. Yes the compile speedup from pch's is nice, but hey... gives me time to refill my water mug at work. Use prefix files, don't use pch files.

15. Pay attention to new releases and possible changed code dependencies

PowerPlant is an evolving framework. Occasionally some code falls by the wayside sooner or later for some reason or other (no time to work on it, engineer transferred to another team, no longer a Metrowerker, obsolete technology (PowerTalk, PowerPart/OpenDoc)). To ease transition, any code that is moving obsolete we try to place into a Will Be Obsolete folder. Next release of PowerPlant, code in this folder becomes obsolete. Obsolete code means that it will no longer be actively developed by Metrowerks, no longer supported, no more bugs fixed, no more features added, no more upkeep, nothing. We'll ship it on the Reference CD in the archives and you're welcome to use it, but Metrowerks no longer supports them.

So to help you make the move, shield this folder and reset your access paths. Make. See what happens. Adjust as needed. Refer to Release Notes and Change Logs for complete details and information. Don't forget the Release Note archives on the Reference CD as mentioned in item 2.


16. When storing in an LArray, use TArray instead. Or if you really must use LArray, don't forget to pass by address.

One of the problems with LArray is its use of void*'s to pass arguments of data to and from the Array. This is needed to allow the storing of any data type, but is hardly typesafe - the void* will allow anything through, and there will be no help from the compiler to alert you to a potential problem situation. This is why TArray was created. It's a wrapper for LArray, but provides an Array class that is typesafe. It also simplifies using the Array classes as having type information allows TArray to handle some aspects for you (such as always providing the sizeof the data).

Another benefit of having type information is the elimination of using void* as an argument. Instead the methods of TArray take the data by its type and then by reference. This eases use in code and improves safety. But if you must use LArray, do remember to pass your data by address and not value. The following snippet should illustrate.

   LArray      theLArray(sizeof(int));
   int         theInt = 3;

      // This is wrong
   theLArray.AddItem( theInt, sizeof(int) );

      // This is right
   theLArray.AddItem( &theInt, sizeof(int) );

      // Or using TArray, this is a bit easier
   TArray<int>   theTArray;

17. Avoid conflicts. Adhere to PowerPlant conventions

Chapter 3 of the PowerPlant Book discusses the PowerPlant conventions. Even if you do not wish to adopt them for yourself, at least be aware of PowerPlant's style so you can know where to look to try to resolve conflict, and/or to avoid conflict altogether. You have a copy of this book on your Reference CD.

18. Erase On Update

Before drawing you ordinarily want to erase what was there before so there is no drawing of ghost and/or incorrect images. As an optimization for most needs, PowerPlant provides the typical topmost view (LWindow) with a feature to Erase On Update. By doing this the entire port is cleaned of artifacts so the subpanes can now draw freely as LWindow::Draw() iterates over them.

If you do not like the flicker this creates, you are welcome to turn the feature off. However, by turning the feature off, you assume the responsibility for erasing the drawing area. This may change the behavior of many Pane classes as they are written upon the assumption of this feature being active.

19. Create Appearance Controls first

With the advent of Themes and the concept of a root control, it is necessary to ensure this root control is truly the first control made in a window. PowerPlant creates a root control in LAMControlImp::MakeMacControl(). Ensure this is called (and hence CreateRootControl) before a call to NewControl is made. If you do not do this, both the call to GetRootControl and subsequently CreateRootControl will fail.

Typically you end up in this problem situation from mixing both Appearance and "Classic" Controls in the same window, e.g. a LWindow with an LStdButton and an LImageWell (respectively, in order of visual hierarchy). More specifically, it is usually because the Standard Control was created before the Appearance Control (hence NewControl is being called before CreateRootControl). This situation often arises if you have an LScroller or LActiveScroller in your PPob and it's created "first" (before any Appearance widgets are). Use LScrollerView instead.

Solutions: 1) Don't mix Control types within a Window. Use all Appearance or all "Classic". 2) Ensure at least an Appearance Control is created first (if you have to, embed a hidden widget like an LSeparatorLine just to force things through). That's about it. We thought through many possible solutions and none were truly optimal, but this worked the best given the nature of the situation (which if you're not familiar with, try DejaNews). IMHO, go with solution one.

20. Use LApplication as it was intended - to manage the Application object

This tip comes from Julien Guimont. He noted that as a beginner, he placed all of his application's behaviors into the Application object. It's certainly very tempting for a beginner to do this as it's very central, provides most of what you need, and you don't really need to branch out much more. Furthermore, if you're coming more from a procedural programming background, this is perhaps a more familiar and comfortable style. Although perhaps effective, it's not very PowerPlant.

Instead, factor your behaviors out to your objects. For example, your windows should be "self-sufficient" and able to manage itself and its own behaviors. Learn to think more about the data and how to manipulate it instead of how to get from point A to point B. If you want some Button to do some thing when some occurrence happens, then have the button Listen for that occurrence instead of some totally unrelated object listening for it and then dispatching to the Button. This is what object-oriented programming is all about.

21. Let LPane come first in class declarations

Greg Dow wrote: "When deriving from LPane (or any subclass of LPane) and one or more other mix-in classes, make LPane (or the LPane subclass) the first base class in the class declaration. For example:

   class MyWindow : public LWindow, public LListener // Right
   class MyWindow : public LListener, public LWindow // WRONG

When creating objects from a PPob resource, UReanimator and URegistrar cast pointers to LPane objects to/from (void*). If the LPane class or subclass isn't the first base c lass, these casts may not work properly."

This is less of an issue today since RTTI is used throughout PowerPlant, but some people still avoid RTTI and use unsafe C-style casts. Be safest and adhere to this rule.

David Phillip Oster

David Phillip Oster I have never met in person, but have interacted with a great deal on comp.sys.mac.oop.powerplant. David's always been one of the active and helpful members of our community of PowerPlant users and readers/posters to the PowerPlant newsgroup. When I posted to the newsgroup asking for contributions to this article, David responded with three lengthy and detailed posts. I was quite happy to have elicited this sort of response (and wondered just how much free time David must have).

With David's permission I am reprinting the full text of his posts. I did perform some editing for typos and layout, but the meat of the following text is all David's. These posts were made to the comp.sys.mac.oop.powerplant newsgroup on 16 January and 18 January, 1999. Although not all of the items pertain directly to PowerPlant, they certainly will aid the PowerPlant developer. David, thanx a bunch.

Here are a few, off the top of my head:

DebugNew is your friend

DebugNew.cp is your friend. Read it, use it. Configure it in your debug builds to do full checking. Learn to interpret its leaks report. Use "NEW" instead of "new".

Assert_() is your friend

Know when to use Assert_() (to catch programmer-time errors) versus when to call Throw_, or one of its variants (to catch run-time errors). Sprinkle your code with Assert_() sanity checks:

   LPane* thePane = someView->FindPaneByID(pane_TheFooPane);
   Assert_(thePane != nil);

This will fire if you munged your resources in Constructor (a programmer-time error). We use Assert_() because if thePane is nil here, then we've got a wildly inappropriate resource and we need to get the programmer's attention to fix it now. But we don't necessarily need to check this in the release build (where debugging, including Assert_(), is turned off) because this error can only happen in the release build if the program is corrupt on disk, and if we are corrupt on disk, all bets are off. Its like checking to see if the power is on. Versus:

   ThrowIfOSErr_(FSMakeFSSpec(0, 0, "\pFooFile", &fooFS));

which is a run time error. The user deleted the FooFile, which we were expecting to be present. We use (a variant of) Throw_ so the program can detect the error, report and recover as appropriate, and keep going.

[The Debugging Classes have a nifty FindPaneByID_() macro that simplifies the former situation.]

Spotlight is your friend

Test with Spotlight. It will show you bugs that nothing else will.

Fat binaries are your friend

Build both 68K and PPC versions of your app. Test them both. This roots out bugs that just happen to work on one architecture or the other because of random chance and the memory layout.

[And do test your 68K binary on a real 68K machine, if you have access to one. I have seen a 68K binary run perfectly under emulation on a PPC but crash horribly on a real 68K. It turned out to be user coding errors, but they would never have been noticed if 68K was not tested under real 68K conditions.]

Scripting is your friend

Since you need to test them both anyway, make your app scriptable, and run it through a test script. When you find a bug, augment your test script so it tests that case and the result. That keeps the bug from creeping back in.

Avoid allocation in constructors. Where it is unavoidable, preflight

Avoid allocation in constructors. Where it is unavoidable, preflight. The Metrowerks C++ runtime doesn't gracefully handle a throw from a constructor. (Since an object is partially built the corresponding destructor isn't called, so that owned sub-objects can't be deleted. Not Metrowerks fault. It is a flaw built in to the C++ language.

  class Ca{
      Ca() { mAp = nil; mAp = NEW LArray; }
      ~Ca() { delete mAp; }

      LArray*   mAp;

   class Cb : public Ca{
      Cb() { mB2p = mB1p = nil; mB1p = NEW LArray;
               mB2p = NEW LArray; }
      ~Cb() { delete mB1p; delete mB2p; }

      LArray*   mB1p;
      LArray*   mB2p;

Suppose we say:

      Cb b;

First the constructor of Ca is called, allocating mAp. Then the constructor for Cb is called, allocating a mBp. The destructors reverse the process.

Now, let's try it again. Only this time, as we allocate mB2p, we run out of RAM, and NEW throws an exception. The destructor ~Cb can't be called, because the run-time system knows that it never finished constructing Cb. So, the super-class destructor is called, mAp is freed. mB1p is never freed. Since we threw because we are low on memory, it is sad that the memory is never freed.

How does PowerPlant handle this problem? It doesn't. Instead it has an LGrowZone class that reserved a 20K emergency buffer. If NEW eats in to the buffer, then the next time WaitNextEvent is called, you'll get a "Memory is Low. Please close some open documents" Alert. The buffer allows PowerPlant applications to eat in the reserve and still successfully allocate. Note that 20K isn't very much, so it is wise to check the free space in the heap before, say, opening a major window.

[There are ways around the situation David illustrated above, such as creating the LArray's as local objects instead of pointers to objects allocated on the heap, performing the allocation in an Init() function that users must call after object creation, or using a class like StDeleter.]

Try to use TArray<LType*> rather than LArray

LArray is sometimes confusing [see item 16 above]. Use the type-safe variant instead.

Use stack based classes like StValueChanger for exception safety

StValueChanger cleanly sets temporarily changed values back to their original value. When you can't use it, consider writing your own stack based class along the same lines, rather than cluttering code with an inline try/catch block. One advantage of the stack-based classes is that you don't need to know what type of exception to catch, cleanup after, and then re-throw. [files such as UMemoryMgr.cp/.h contain many stack-based classes].

Avoid calls to NewRoutineDescriptor(), use BUILD_ROUTINE_DESCRIPTOR

NewRoutineDescriptor() allocates memory, and if called in a loop can be a source of memory leaks. Build your own macros like this:

#define DeclareModalFilterUPP_(var, proc) \
   static RoutineDescriptor   var##RD = \
                           (uppModalFilterProcInfo, (proc));\
   ModalFilterUPP             var = (ModalFilterUPP) &var##RD

#define DeclareModalFilterYDUPP_(var, proc) \
   RoutineDescriptor          var##RD = \
   ModalFilterYDUPP         var = (ModalFilterYDUPP) &var##RD

#define DeclareModalFilterUPP_(var, proc)     \
            ModalFilterUPP     var = proc
#define DeclareModalFilterYDUPP_(var, proc)     \
            ModalFilterYDUPP   var = proc

Call them like this:

DeclareModalFilterUPP_(ucStandardFileModalFilterUPP, StandardModalFilter);

DeclareModalFilterYDUPP_(ucStandardFileModalFilterYDUPP, StandardModalYDFilter);

This defines variables named ucStandardFileModalFilterUPP and ucStandardFileModalFilterYDUPP which you can use in either 68K or PPC code, that are initialized at run time to either a procedure pointer or a universal proc pointer. Putting the macro definitions in a header file keeps the clutter out of your code.

Ignore constructor, use Rez.(or: #define is your friend)

If your define all your resources except pictures in Rez, then you get access to the C preprocessor. This gives you a number of advantages:

  1. You get consistent symbols between your PPobs and C++ code. Just include a header file written in the common subset of both languages and your paneIDs will be consistent, from C++ to Rez.
  2. You can use search and replace and spell checkers on your strings.
  3. You can parameterize your resources by target. (I build both the Pro and Regular versions of ImageAXS from the same source. In the header of each target I #define TARGET PRO or #define TARGET REGULAR and include Header.h. It has:
   #if PRO == TARGET
      #define programS "ImageAXS Pro"
   #elif REGULAR == TARGET
      #define programS "ImageAXS"
      #error unkown target

Then, in all my dialogs, strings, and menus, I build up the strings I need with expressions like:

   resource 'MENU' (kAppleMenu show_Apple) {
      kAllItems - (kItem2) ,
      {   /* array: 2 elements */
          /* [1] */   "About " kProgramS "S∨", kMenuItemStuff,
          /* [2] */   "-", kMenuItemStuff

That way, if the program name changes during development, I just change it in the header, and know the change is correctly applied through the whole program.

A similar trick separates out language dependent information (mostly strings and the screen rects that need to grow to accommodate long ones.) Another similar trick separates out style guides: you want a gutter of 4 pixels between items, and a 10 pixel border around all the items of the window? Just specify their positions using a #define macro that is an arithmetic expression of appropriate constants. Once you get in to this mode of thinking, you can design your own resource types that are compatible with Reanimator, and use it for persistent storage.

Make PowerPlant read-only

Use a version control tool, or a tool like File Buddy to set all the source code of PowerPlant (headers and .cp files) to be read-only. That way, you won't accidentally modify it. This will save you trouble when a new version of PP comes out and you want to upgrade.

[I prefer a version control tool as Finder locks are annoying. Furthermore, having PowerPlant in version control helps ensure your PowerPlant stays in sync, tracks any changes you might make to the PowerPlant sources, and if you're working in a multi-developer situation, ensures all team members are using the exact same PowerPlant.]

Adding your own code to a basic PowerPlant class with mix-in classes

Balloon Help is great for letting a user know what some graphical object on one of your windows does. It is even better for letting the user know why some object is disabled. Unfortunately, the Mac Toolbox support for Balloon Help only allows for a single disable string, so programmers generally put in a catch-all string listing all of the reasons that an object might be disabled.

A better way is, in your Balloon help support, try to dynamic_cast the pointer to the object that the mouse is currently over to CBalloonHelpMixIn. Recurse up the view hierarchy trying to dynamic_cast, until you get a non-nil pointer. If you get a non-nil pointer, call the BalloonCommandStatus() method, passing in the paneID. Then, in your classes, mix-in CBalloonHelpMixIn as an super-class, as appropriate, and implement BalloonCommandStatus(). This lets your window, or some portion of it, return a Balloon Help Record, referencing a 'STR#' and strID, so that the Balloon Help system can explain to the user exactly why he can't do that right now.

By implementing this as a mix-in class, you write functionality once, where you need it, and mix it in to all of your windows and views that need it. An alternative would be to actually go into the source for LPane or LView. But, then you'd have trouble moving your changes to the next version of PowerPlant.

Adding your own code to a basic PowerPlant class by editing a PowerPlant file

If you really need to change something in PowerPlant, create a PP Overrides folder, and put it ahead of the PowerPlant folder in the Access Paths panel of the Target(s)' Settings. That way, your modified version of LPane.cp will be found before the official one. It will be in a separate folder, so that when you go to a new version of PowerPlant you won't accidentally overwrite it, and you'll be able to quickly compare your file with the official one to see if your changes are still appropriate.

Read the source code for PowerPlant

Often, when you have a design problem, you'll find that the designers of PowerPlant have already coped with that problem or a similar one, so you'll find a debugged pattern for solving your problem.

For example, in ImageAXS Pro an ImageAXS Pro document has many windows, and when the last window is closed, the document should close. But, when the app is closed, it closes all open documents, and when the document is closed, it closes all open windows. If you just wrote the code naively to handle the first case, you'd get in to a situation where the destructor of the window called the destructor of the document and the destructor of the document calls the destructor of the window. This is not only an infinite loop, but it is a call to a destructor of an object that has already been deleted (so DebugNew helps you crash early, while enough of the environment remains so you can still see what is going on). It's bad.

Let's look inside the source code of PowerPlant to see how it handles an analogous problem: Listeners and Broadcasters similarly keep track of each other, also LArrays and LArrayIterators. By making the window a Broadcaster and broadcasting the message msg_BroadcasterDied just before it dies (with itself in the refCon of the message), the document can clear out its pointer to the window and decide whether to die too (since it clears its pointer, its destructor will no longer try to destruct the now dead window.)

LSharable is another choice: if you re-write the way you handle assignments to variables, LSharable implements reference counting with deletion when the reference count is zero.

The Broadcaster/Listener pattern was a better fit for my application.

Read it again

When you get a new release from Metrowerks, read the source again. Metrowerks often adds new methods to existing classes and entirely new classes, and the best way to find out what is new is to read the source code.

Hope This Helped

What you've read here may or may not be news to you. If it is new, I'm glad that you've learned something new. If it's all old-hat to you, consider sharing some of your knowledge and experience with others on forums like comp.sys.mac.oop.powerplant to help further the community. And if you already share on the newsgroups, I'll see you there.

I'd like to thank DejaNews for its services; David Phillip Oster for his permission to reprint his postings; Greg Dow for correcting me (a lot), and letting me reprint some of his tips (read the TechNotes, you'll see).

If there's any single item I'd like you to remember from this article, not only should you read the PowerPlant source, but just make sure you read the Release Notes.

And then read them again. :-)

Happy programming!


  • Daub, John. "Arrays, Iterators, and Comparators... Oh My!" MacTech Magazine. Vol 15, No. 2. February, 1999.
  • Daub, John. "The Ultra-Groovy LString Class" MacTech Magazine. Vol 15, No. 1. January, 1999.
  • Daub, John. "What Is PowerPlant?" MacTech Magazine. Vol. 14, No. 12. December, 1998.
  • Metrowerks Corporation. Constructor Manual. 1998.
  • Metrowerks Corporation. PowerPlant Book. 1998.
  • Metrowerks Corporation. PowerPlant Reference. 1998.
  • Metrowerks Corporation. C Compilers Reference. 1998.
  • <>
  • <>
  • <>

John C. Daub is one of Metrowerks Corporation's PowerPlant engineers. He finds he enjoys framework authoring a little too much to be considered healthy. You can reach John via email at


Community Search:
MacTech Search:

Software Updates via MacUpdate

BusyContacts 1.6.4 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
Steam 4.0 - Multiplayer and communicatio...
Steam is a digital distribution, digital rights management, multiplayer and communications platform developed by Valve Corporation. It is used to distribute a large number of games and related media... Read more
OmniGraffle Pro 7.19.3 - Create diagrams...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
OmniGraffle 7.19.3 - Create diagrams, fl...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
Hopper Disassembler 5.3.3- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
calibre 5.35.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Sound Studio 4.10.0 - Robust audio recor...
Sound Studio lets you easily record and professionally edit audio on your Mac. Easily rip vinyls and digitize cassette tapes, or record lectures and voice memos. Prepare for live shows with live... Read more
Sparkle Pro 4.0 - Visual website creator...
Sparkle Pro will change your mind if you thought building websites wasn't for you. Sparkle is the intuitive site builder that lets you create sites for your online portfolio, team or band pages, or... Read more
Dropbox 140.4.1951 - Cloud backup and sy...
Dropbox for Mac is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files... Read more
FotoMagico 6.0.5 - Powerful slideshow cr...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more

Latest Forum Discussions

See All

‘Horizon Chase’ China Spirit DLC Release...
Following the release of the excellent reveal of the Horizon Chase Senna Forever expansion, the game will be getting a new DLC on mobile platforms today. Today, the Horizon Chase China Spirit DLC pack will release on iOS and Android bringing in 9... | Read more »
‘PUZZLED’ from SNK and Hamster Is Out No...
Following ZED BLADE ACA NeoGeo earlier this month, SNK has brought over another game in the ACA NeoGeo series to both iOS and Android in the form of PUZZLED. SNK and Hamster originally brought the series to mobile with Samurai Shodown IV, Alpha... | Read more »
A House Full of Covid – The TouchArcade...
It’s been a rough week as both of our young children tested positive for Covid, and since recording this early on Friday my wife has tested positive now too. Thankfully the kids seemed to recover fairly quickly and are mostly back to normal, and I... | Read more »
TouchArcade Game of the Week: ‘Krispee S...
Krispee Street is a new hidden object game from Frosty Pop that is based on their popular and almost painfully sweet webcomic Krispee. This is one of the latest titles to be added to the Netflix Games catalog, which means you’ll need to log into... | Read more »
SwitchArcade Round-Up: ‘Escape Lala’, ‘B...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 21st, 2022. In today’s article, we’ve got a lot of new releases. A lot. There were eight on the schedule when I went to bed last night. There were twenty-four when I woke up... | Read more »
Beta Testers Needed for Huge Version 2.0...
Ya’ll remember Dungeon Raid, right? The phenomenal matching RPG hybrid that launched on mobile more than a decade ago, but was more or less abandoned by its developer only to die a slow death on the App Store before the 32-bit Appocalypse finally... | Read more »
‘Ark Legends’ Gives Players a Chance to...
It’s Airpods and Amazon gift cards galore as Melting Games opens pre-registration for Ark Legends. The upcoming mobile RPG is giving away tons of in-game goodies such as gold, energy, iron core, hero summon chest and rare iron core to players who... | Read more »
‘Nickelodeon Extreme Tennis’ Out Now on...
Nickelodeon Extreme Tennis () from Old Skull Games and Nickelodeon is this week’s new Apple Arcade release. Nickelodeon Extreme Tennis features characters from old and new Nickelodeon shows including SpongeBob, TMNT, and many more. The tennis game... | Read more »
SwitchArcade Round-Up: ‘RPGolf Legends’,...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 20th, 2022. In today’s article, we’ve got a massive amount of new releases to check out. We’ve got summaries of all of them, from heaven to hell. We also have the lists of... | Read more »
‘Zed Blade ACA NEOGEO’ Review – Well, It...
SNK’s NEOGEO platform played host to a great many classics, both famous and under-the-radar. The Metal Slug games. The King of Fighters series. Magician Lord. Shock Troopers. Sengoku 3. NEO Turf Masters. Fatal Fury. Samurai Shodown. Twinkle Star... | Read more »

Price Scanner via

Verizon’s 2022 iPad promo: $100-$310 off any...
Verizon has cellular-capable iPads on sale for $100-$310 off MSRP when purchased with an Unlimited service plan. Sale price is applied to your account monthly over a 24 or 30 month period, depending... Read more
Sunday Sale: Apple AirPods are on sale for up...
Amazon has Apple AirPods on sale for $10-$100 off MSRP today, depending on the model. All are in stock today with free delivery: – AirPods Max headphones (Blue): $449 $100 off MSRP – AirPods Max... Read more
These Apple resellers are offering 13″ M1 Mac...
Apple resellers are offering discounts on 13″ MacBook Pros with M1 Apple Silicon processors ranging up to $150 off MSRP. Here’s where to get one today: (1): Apple’s 13″ MacBook Pros with M1 Apple... Read more
Amazon lowers prices on select 13″ M1 MacBook...
Amazon has select Apple 13″ M1 MacBook Airs on sale for $150 off MSRP this weekend, starting at only $849. Their prices are the lowest available for new MacBook Airs today. Stock may come and go, so... Read more
Apple has 13″ M1 MacBook Airs back in stock s...
Apple has restocked a full line of 13″ M1 MacBook Airs, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the cheapest M1-powered MacBooks for sale today at... Read more
In stock and on sale! 16″ 10-Core M1 Pro MacB...
Amazon has new 16″ 10-Core/512GB M1 Pro MacBook Pros in stock today and on sale for $50 off MSRP including free shipping. Their prices are the lowest available for new M1 Pro 16″ MacBook Pro from any... Read more
Deal Alert!: 14″ M1 Pro with 10-Core CPU in s...
Amazon has the new 14″ M1 Pro MacBook Pro with a 10-Core CPU and 16-Core GPU in stock today and on sale for $2299.99 including free shipping. Their price is $200 off Apple’s standard MSRP, and it’s... Read more
Apple has 24-inch M1 iMacs (8-Core CPU/8-Core...
Apple has restocked a wide array of 24-inch M1 iMacs with 8-Core CPUs and 8-Core GPUs in their Certified Refurbished store. Models are available starting at only $1269 and range up to $260 off... Read more
Select 24″ M1 iMacs are on sale for $100 off...
Sales of Apple’s new 24″ M1 iMacs have been rare since its introduction, perhaps due to global supply issues. However, B&H is offering a $100 discount on select 24″ iMacs, and they’re in stock... Read more
M1 Mac minis are back in stock today at Apple...
Apple has M1-powered Mac minis available in their Certified Refurbished section starting at only $589 and up to $140 off MSRP. Each mini comes with Apple’s one-year warranty, and shipping is free: –... Read more

Jobs Board

Registered Nurse (RN) Employee Health PSJH -...
…is calling for a Registered Nurse (RN) Employee Health PSJH to our location in Apple Valley, CA.** We are seeking a Registered Nurse (RN) Employee Health PSJH to be Read more
Systems Administrator - Pearson (United State...
…and troubleshoot Windows operating systems (workstation and server), laptop computers, Apple iPads, Chromebooks and printers** + **Administer and troubleshoot all Read more
IT Assistant Level 1- IT Desktop Support Anal...
…providing tier-1 or better IT help desk support in a large Windows and Apple environment * Experience using IT Service Desk Management Software * Knowledge of IT Read more
Human Resources Business Partner PSJH - Provi...
…**is calling a** **Human Resources Business Partner, PSJH** **to our location in Apple Valley, CA.** **Applicants that meet qualifications will receive a text with Read more
Manager Community Health Investment Programs...
…is calling a Manager Community Health Investment Programs PSJH to our location in Apple Valley, CA.** **Qualified candidates will be invited to do a self-paced video Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.