How to avoid post-construction by using Parts Factories.

I did my first GUI programming on an Atari 1040ST, using Modula-2 and MC68000 assembly language, focusing on such immensely interesting things as implementing general windowing, a resonable blitter interface, raw mouse and non-buffered keyboard access, smooth text cursor and scrolling, and so on, basics that (except for the latter two, or three or four) nowadays e.g. Windows provides, and that in most cases nowadays is down at abstraction levels that you seldom if ever visit. But on the Atari e.g. the quality of printed output depended on the program; each program did it It’s Own Way™. This was around 1986/1987, I was a student and I could not afford a PC, not even a harddisk, much less a Mac (my plan was to convert the Atari to a Mac on-the-cheap, through some half legal means, but I never got that far).

Oh, joys of the PC in the 1990s! Except for lacking coroutines Borland’s Turbo Pascal was much more practical and appealing than Modula-2, and Windows could do so much more – like general windowing, and like printing! I almost replaced Niklaus Wirth with Anders Hejlsberg as my programmer idol (Anders Hejlsberg later defected from Borland to Microsoft, creating the C# language; it’s as if he made a second try at expressing one general idea, the first time with Wirth’s Pascal as his starting point and the second time with Gosling’s Java as his starting point, managing to create much the same “feel” in two languages that at first glance appear to be very different, but which successively filled the same niche).

And, joys of the long-winded rambling introduction! :-) Anyways, with Borland’s OWL framework, as well as with Microsoft’ MFC framework, constructing a window object was a two-step procedure. First, you constructed your “blank” Pascal or C++ object (OWL was available for both languages, MFC only for C++), like building a house without electrical wires and plumbing. And then you called some init method to create a corresponding API-level window, managed by your object, like opening the walls and floors of your new house to stuff in the missing electrical wiring and plumbing. We may laugh today at this totally impractical and error-prone create-unusuble-and-then-fix-it-up Rube Goldberg like idiocy. Or, we could have laughed at it, except that that’s still how it’s most often done!

Two-phase construction

A minimal MFC application (complete code):

#define WINVER  0x0500      // Windows 2000 and up.
#include <afxwin.h>         // MFC core and standard components

typedef CFrameWnd   MainWindow;

class App
    : public CWinApp
{
private:
    bool createTheMainWindow()
    {
        static char const title[]   = "A general top level MFC window";
        MainWindow* const pWnd      =
            new MainWindow;             // Step 1: C++ object creation.
        if( !pWnd ) { return false; }   // Pre-standard 'new' in MFC...
        m_pMainWnd = pWnd;
        pWnd->Create( NULL, title );    // Step 2: The virtual "init" call.
        return true;
    }

public:
    virtual BOOL App::InitInstance()
    {
        CWinApp::InitInstance();

        if( !createTheMainWindow() ) { return false; }

        m_pMainWnd->ShowWindow( SW_SHOW );
        m_pMainWnd->UpdateWindow();
        return true;
    }
};

App theApp;

MFC is still extant, and as the code above shows it’s rather heavily oriented towards two-phase construction. Not only window objects but also the application object (like the theApp object above), and almost any MFC object, is constructed in two steps: a kind of dummy C++ object construction followed by a virtual “real initialization” call, which I’ll refer to as init. And in the code above the application object’s init is itself n-step!

This leads to a host of problems, problems that tend to crash your app, e.g. virtual calls on methods of as yet only half-initialized objects (not uncommon in Microsoft’s ATL and ATL-based WTL, which are its slightly less archaic alternatives to MFC), and checking everywhere of whether you have a fully initialized object, so, why, Why, WHY?

Well, perhaps they didn’t know better. Or perhaps they assumed that ordinary programmers, at the time, would find it too difficult to relate to more safe but also slightly more advanced ideas, ideas whose explanations often included “academic” terminology such as “class invariant”. Here I discuss one such, which I call Parts Factories, and in my next posting I’ll discuss another, namely the cppx library’s C++98-compatible support for constructor argument forwarding.

The problem: DBDI (dynamic binding during initialization)

The problem addressed by two-phase construction is how to do derived class specific initialization at some point within a base class initialization, e.g. how to create a Windows API button control somewhere within the initialization of a general C++ Widget object. Marshall Cline, in the C++ FAQ, calls this DBDI, short for Dynamic Binding During Initialization. One of the solutions he presents is two-phase construction (but of course with advice to wrap that in factory functions instead of MFC-like in client code, plus advice to use smart pointers, and he also presents some other more safe solutions, including Parts Factories).

That FAQ item is Marshall’s writing, but I think of it as 50% “my” FAQ item since I once convinced Marshall to include it in the FAQ – it’s (at least so far) my main contribution to our FAQ.

However, my original suggestion to Marshall was for discussing only Parts Factories. Marshall, wisely, took a broader view. It’s worth reading.

Parts Factories

What I call Parts Factories is an invasive solution where your class T is designed to support DBDI. The idea is to pass a derived class specific factory object to the T constructor, with a reasonable default if that’s desired. For example, passing a factory for API-level widgets, producing the kind of widget that’s suitable for the derived class in question:

A minimal parts factory example (complete code):

#include <stdio.h>

namespace apiLevel {
    enum Handle {};

    Handle newButton( char const title[] )
    {
        printf( "apiLevel::newButton(\"%s\")\n", title );
        return Handle();
    }

    Handle newListbox( char const [] = "" )  { return Handle(); }
    Handle newStatic( char const [] = "" )   { return Handle(); }
}  // namespace apiLevel

class Widget
{
private:
    apiLevel::Handle    handle_;

protected:
    struct ApiWidgetFactory
    {
        virtual apiLevel::Handle newWidget( char const title[] ) const
        {
            return apiLevel::newStatic( title );  // Reasonable.
        }
    };

public:
    explicit Widget(
        char const                  title[] = "\"? (unspecified)\"",
        ApiWidgetFactory const&     factory = ApiWidgetFactory()
        )
        : handle_( factory.newWidget( title ) )
    {}
};

class Button
    : public Widget
{
protected:
    struct ApiWidgetFactory: Widget::ApiWidgetFactory
    {
        virtual apiLevel::Handle newWidget( char const title[] ) const
        {
            return apiLevel::newButton( title );    // Derived class specific.
        }
    };

public:
    explicit Button(
        char const                  title[],
        ApiWidgetFactory const&     factory = ApiWidgetFactory()
        )
        : Widget( title, factory )
    {}
};

int main()
{
    Button  button( "Just a button" );
}
 

As the main routine shows the usage is very simple. And it ensures that when you have a Button object (say) at hand, then it’s fully initialized. It’s also a type safe technique: there’s no way to pass a factory producing listbox widgets, say, to the Button constructor.

One main idea for the type safety is to maintain to a kind of “nested” hierarchy of factory classes, as shown above. This might seem to be a bit of work. However, most of that code will be somewhere anyway. The overhead is small. And since it simplifies the usage and provides safety, it’s a net win.

What about modal dialogs?

I first investigated Parts Factories as a GUI framework technique in a small Windows API-level application I called “Alf’s ScreenSaver Manager” (it’s available on CNET, amazingly it’s still being downloaded!). And there the problem of modal dialogs popped up, so to speak. The key insight is that at the C++ level a modal dialog type can be modeled as a function, not a general window. Otherwise, if you can instantiate objects of a modal dialog class, and call Run methods on them, then before and after you have a partially unusable object, a dangerous half-initialized or half-destroyed thingy. The function to run a modal dialog of type T, with access to construction of T instances, can of course be a single function template, and that’s what I chose.

Generalization

In the DBDI FAQ item Marshall discusses not Parts Factories as such, but a generalization where instead of e.g. newWidget you can have any method, any method that does something derived-class specific.

But I think the concrete GUI context is key to really grokking this.

After all, most of our object oriented techniques, although they originated with the Norwegian Simula language for doing simulations, were brought into the mainstream by GUI programming, in particular by the Smalltalk project at Xerox PARC in the 1970’s. Oh, and that lets me quote somebody! :-) Herewith, Bertrand Meyer on OO:

Born in the ice-blue waters of the festooned Norwegian coast; amplified (by an aberration of world currents, for which marine geographers have yet to find a suitable explanation) along the much grayer range of the Californian Pacific; viewed by some as a typhoon, by some as tsunami, and by some as a storm in a teacup – a tidal wave is hitting the shores of the computing world.

– Enjoy!

About these ads

One comment on “How to avoid post-construction by using Parts Factories.

  1. Regarding the ScreenSaver Manager app mentioned above: as of 25th June 2010 disabling the screensaver (which is the main thing that it does) has stopped working in Windows XP, in that the screensaver kicks in anyway… This “oops it stopped working” is the same as HTML+time, the ftype delete option, the netstat command, the openfiles command, and so on and so forth, all crippled or removed by Windows updates. The remarkable thing is that (hold fast) I do not have Windows updates enabled, since Windows updates is one of the “technologies” that was crippled by a Windows update, perhaps in order to ensure that people would upgrade their computers; so I suspect that it’s the Microsoft Security self-updating, which by the way stops my computer for 15 to 20 minutes each day (it requires an extreme incompetence to do an incremental update that inefficiently!), that is the culprit. Oh well, the ScreenSaver Manager was never meant to last eternally; t’was good while it lasted.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s