Boost logo

Boost :

From: jackthompson99 (JMThompson_at_[hidden])
Date: 2002-01-24 01:04:46


Hey guys,

I sent an e-mail to Dr. Stroustrup a couple nights ago, and he
replied, "Have a look at boost.org. They exist specifically to
provide better libraries in the context of the C++ standard library
and to act as a test bed for new library ideas".

So, here I am. I've installed and built my boost libraries, and I'm
trying to figure out how to dig in.

Anyway, here's what I was telling the Dr.

        I've been using C for about a decade, and C++ for about 7
yrs. I'm a huge fan of your invention, and I honestly feel like your
name should eventually be as well known as Tesla and Edison. And the
Standard Template Library is an incredibly well engineered system. I
have a way to use it that is generic enough that it may be a
candidate to be another standard. I know that's a lot to say. I'd
like to explain it briefly, but first I should explain why I find it
useful.

        Since I started working with assembler, I've always felt like
the language I was using was missing something. I've used an
assortment of languages, and it seems like they are all missing the
same thing. The main part isn't really missing from C++, it's just
not commonly understood. The concept of virtual construction is the
core of the issue. Now I know that this problem is solved, but it
really could stand for just one more thing to wrap it up into
something usable for any ordinary C++ developer….

        Using a virtual constructor by way of a template, a developer
can easily create any kind of object based on any type of identifier,
but what good is that when the developer has exhausted all of his
efforts on just building a simple system to dynamically create
objects. The developer needs a way to organize these objects,
without building another data warehouse. And I have never heard of a
complicated database that shouldn't be fully hierarchical. So, the
system should be one hundred percent re-entrant.

        Well, I have such a beast. I'm not done with it yet. I'm
just now finishing up a project for Textron, where some of this
concept was cultivated into my skill set. I am having a rough time
explaining the system to my boss, and I'm in a real bind, but that's
another story. The main thing that I've learned from this job is
that the world needs to come together on one simple international
standard for dealing with data and persistent C++ objects.

        I've used my ClassFactory / DataStore system as a foundation
for another library that I call the WinFactory. This system simply
uses the ClassFactory / DataStore as a database manager. The objects
held in the database are simply graphical user interface components.
This worked out really well, `till by boss took it apart. But I have
a version of it that I'm re-writing at home that is much better. The
database can be held either in a simple text format, resembling
hypertext, or a binary file. The system relies heavily on the memory
manager, so fast memory allocation is required.

        I have also populated an MFC user interface with data held in
these objects. The system seems to be able to flex with just about
anything, and I feel like it could at least contribute to discussions
about new standards that are based on your standards. By the way, I
need to find a team that I can work with who has good work ethics and
integrity. Suggestions would be much appreciated.

.....

So, I've looked at the library list in Boost, and haven't recognized
anything like what I've built. I'm going to explain the system that
I'm going to create for Boost.org.

The main concept behind the system is a warehouse environment. The
warehouse has isles of goods. Each isle is any length, and each isle
contains exactly one type of product. And every product contains a
single pointer which is initally NULL. This makes it so that when
you pull the product off the shelf and open it, you will see whatever
the product is ( characters, integers, strings, etc. ), and you will
find one more thing. It's called the nest. Now, until you try to
use the nest, it's empty (NULL). But when you need it, it is
created. What is this nest you ask? It's another warehouse. Just
like the one that it is contained within.

So, the entier concept is one hundred percent re-entrant. This makes
it easy to build hierarchical infrastructures. The objects can be
virtually any C++ thing. They persist with the greatest of ease to
simple IO objects.

User interfaces are easy to build with this system. Content editors
view it as a script. C++ programmers view the script as C++ objects.

Again, I need to finish re-writing the system, and I need to document
it. But I feel like it is a candidate to become another Boost
library.

The main thing that is accomplished here is that I have just one
database system that can used for every aspect of a typical
application. Since the product of the factory is a simple C++
object, it can, of course, hold virtually any other C++ object. So,
the object could be an animated button on the screen, or a phone
number, or any other object you want.

Here's the catch. All products are based on the Primitive base
class. All Primitives are based on a root class that maintains the
objects identification. The identification could be anything, but
they should all be the same (mutable). And, the Primitive base
class needs to be constructed with a reference to the Products parent
(the product list).

The primitive base defines a few virtual functions, including
        
The = operator lets the coder turn an entire DataStore object off or
on. All Products involved will be switched.

Of course, you can turn on or off any node in the hierarchy

The Fields() function is used to cause every data member to persist
in storage.
Each member gets the following function call in Fields()
        Field("ConcreteType",ConcreteType); // ConcreteType can
be any type defined in the factory's parser and IO objects.

Here is a sample:

// Home.h
class Object: public Primitive
{
public:
        Object(ProductList& pl) : Primitive(pl) {}
        virtual bool Fields();
private:
        int MyInt;
        string MyString;
        vector<string> MyStringVector;
        // many more types are defined, and any developer can add on
};

Robot(Object,"Object") // I don't like macros, but this one is worth
it. It expands to about three lines.

bool Object::Fields()
{
        //The Primitive base defines Fields as pure virtual, so first
derivatives can't call it. Anything based on this class should call
this classes Fields().

        // These will serialize in the proper direction based on the
return of IsLoading()
        Field("MyInt",MyInt);
        Field("MyString",MyString);
        Field("MyStringVector",MyStringVector);

        return true; // false on error
}

Now, the data can be saved in text format or binary. Binary is
simple. Each item is written to and read from the disk with it's
identifier.
The text format is simple too, approximately the same thing happens,
but it's formatted in a sort of hypertext style… Here is what the
above data could look like:

<Object:MyObjectName;
        MyInt:29349;
        MyString:Some string
with new lines.; // still ends with a semi\n. – semis in
string are parsed into #xxx;
        MyStringVector:fisrt string;
        MyStringVector:second string;
> // end MyObjectName

Ok, so some typical weaknesses are evident. But dealing with the
semi is no big deal, and the redundancy in the MyStringVector names
could be changed. But look what it gives you….

So far, no big deal. We can all write parsers. Here's the cool
part. This object can have babies. Any type of babies. Could be
the same type, could be different. Here's how it looks when it has
children:

<Object:MyObjectName;
        MyInt:29349;
        MyString:Some string
with new lines.; // still ends with a semi\n. – semis in
string are parsed into #xxx;
        MyStringVector:fisrt string;
        MyStringVector:second string;

        <AnotherTypeOfObject:FirstBorn;
                // Might not have any data.
> // end FirstBorn
> // end MyObjectName

And, if the FirstBorn has children…

<Object:MyObjectName;
        MyInt:29349;
        MyString:Some string
with new lines.; // still ends with a semi\n. – semis in
string are parsed into #xxx;
        MyStringVector:fisrt string;
        MyStringVector:second string;

        <AnotherTypeOfObject:FirstBorn;
                // Might not have any data.
                <Object:YesAnotherObject;
                        MyInt:922039;
                        // leave the other fields with default values
>
> // end FirstBorn
> // end MyObjectName

Ok, so let's say we have this file on the disk, and we'll call it
FamilyTree.txt. Here's the code to load it:

void funk()
{
        PathString FileName("FamilyTree.txt")
        Input in(FileName,text);
        DataStore ds;
        ds<<in;
        if (Monarch.Error()) return; // error occurred somewhere
}

and here's how it can be saved;

void funk()
{
        PathString FileName("FamilyTree.txt")
        Output out(FileName,text);
        DataStore ds;
        ds>>out;
        if (Monarch.Error()) return; // error occurred somewhere
}

Now you data store has a map<Identification,ProductList*>, and some
methods to index and search. One very common scenario is the coder
knows what kind of object he is looking for in the data store. So,
to get the stores list of type Object, do this:
        ProductList& pl=ds["Object"]; error will return an empty
product list

The Product list is a simple vector of Primitive*. If you know that
you are looking for MyObjectName in the list of Objects, just do this:
        Object& o=(Object&)pl["MyObjectName"];

It is important to check for errors here like this:
        if (o.Error()) {/*error handler */}

if it passes that check, then the Object is safe. Otherwise o is
actually the ErrorProduct that is safely held in the DataStore's
Monarch.

The DataStore and Product list are just simple map<> and vector<>
implementations. The Factory system is no magic either. It just has
a list of robots, and those robots are virtual constructors. The way
the nest is created is by the use of a pure virtual base class that
is defined before the Primitive. The DataStore is derived from this
base. This makes it so that the Primitive can call the DataStore by
it's pure virtuals. There are only a handful of things that ever
need to happen in this scope. They are mainly construction,
destruction and on/off using the assignment operator with a boolean
parmameter.

About the list boxes and treeview controls I mentioned. I have built
two versions so far, one for the MS Windows common controls, and one
for the MFC TreeView and ListView controls. They do much the same
thing. Basically, you don't ever need to think about those
intricacies again. This think of it as a DataStore. The tree view
is loaded as if it is just another object, and populated with another
DataStore, or the same one. It's incredibly simple to use. And it
means that all of the applications' data can be organized in one
simple system.

The average GUI is nothing more than a hierarchy of windows. Some
are tree controls, some are buttons, some are sliders, some are text
windows, some are images, etc. The concept is the same:
<Window:Main;
        <Window:SubWindow;
                <TreeView:TreeInSub;
                
        DataStorage:http://www.jackmthompson.com/menu.cfx; //
could be anywhere. Input object needs support for every protocol
>
> // SubWindow
> // Main

The possibilities are endless, `cause the ClassFactory / DataStore
system has doesn't care what type the objects are. That's what the
Robots are for.

So, I don't know if this is the best way to do it, but we do need
something simple that uses ONLY C++. The parser could probably be
faster and smaller, but the concept is rock solid.

What do you think?????


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk