Why?

Well, somehow all these MFC-a-likes are not fun anymore... but seriously.

A traditional GUI application is usually built as a big, highly polymorphic hierarchy of classes. Often, a set of the well established design patterns is applied to this process. To assist this development strategy, there is a number of huge hierarchical frameworks such as MFC, wxWindows, etc. These frameworks provide a set of standard GUI elements that can be used as base classes. This "subclassing" approach can be illustrated with the following example that customizes the button's background.

//default button
struct button
{
    ...default button features
};


//button with a custom background color
struct button_with_custom_background : button
{
    ...customize background
};

Suppose, we now want to have the standard button but with an image. We can create another button class.

//button with image
struct button_with_image : button
{
    ...customize the button drawing
};

It worked fine but what if later, we needed to implement the standard button with custom background and image. Obviously, we cannot just write:

struct button_background_image
    : button_with_custom_background
    , button_with_image
{
    ...
};

This illustrates a general problem with polymorphic subclassing. Of course one can always use pointers, but it won't look nice. The type safety of these frameworks is not very strong, to say the least. Notus is suggesting another approach. It can be described as a process of specifying a set of interchangeable GUI "parts". The C++ compiler then generates and combines these parts according to the provided specifications. Obviously, the specifications are described in terms of C++ templates. The whole idea is similar to the industrial manufacturing process like designing and building a car. In the above example, the notus approach would look like the following pseudo-code.

struct my_background
{
    template< typename Window >
    void draw( Window& w ) {...}
};


struct my_image
{
    template< typename Window >
    void draw( Window& w ) {...}
};

We just created two interchangeable GUI parts. They are interchangeable because they can be used with any window not just buttons and can be easily replaced with another implementation. We can now combine all our parts together in any way we like.

typedef view< button
    , my_background > button_with_custom_background;

typedef view< button
    , my_image > button_with_image;

typedef view< button
    , my_background
    , my_image > button_with_background_and_image;

We can build other parts such as edit control with custom background.

typedef view< edit
    , my_background > edit_with_custom_background;

Since the final structure of the GUI application is generated at compile time, polymorphism is not an essential requirement anymore. Indeed, polymorphism is a way to abstract or classify a concrete class. Polymorphism is essential for traditional object oriented design because otherwise, we would have to implement separate routines for all possible concrete classes. With templates, we can just use the concrete classes directly and the compiler will generate code for each of the concrete combinations as needed. In Notus, a virtual method is an exception, not a rule.

The compiler is making sure that all our parts fit together. So, we potentially get a very strong type safety. And if the compiler was able to put all this stuff together, then there is a good chance that the program will be much more stable.


Copyright Eugene Gladyshev, 2004

SourceForge.net Logo