Node: A Simple Data Base Example, Next: , Previous: Using Lpp, Up: Introduction



A Simple Data Base Example

In this example we create a class that implements a simple data base. We then create an instance of the data base and populate it with some entities, namely some people. And finally we generate a report on the people of a family that we used to populate the data base to show the relational aspect of the data base.

Lpp is useful here since we want entities to be any kind of object and hence dynamically bound objects will index the data base. In the example we use Lpp symbols to designate entities. We set relations in the data base with a typical entity attribute value tuple. So the data base access member functions are as follows

Here is the implementation of the data base class

     
     /////////////////////////////////////////////////////////////////
     // main.cc = Introduction Simple Data Base example.
     
     #include <Lpp.hh>
     
     // Data Base class.
     class DataBase {
       int size;
       let contents;
     public:
       DataBase();
       int getSize() {return size;}
       void addEntity(let);
       void setValue(let, let, let);
       let getValue(let, let);};
     
     // Data Base constructor.
     DataBase::DataBase() {size = 0; contents = makeHashTable();}
     
     // Add an entity to the Data Base.
     void DataBase::addEntity(let entity) {
       if (!gethash(entity, contents)) {
         puthash(entity, contents, 0);
         size++;}}
     
     // Set the value of an attribute for given entity.
     void DataBase::setValue(let entity, let attribute, let value) {
       let attributes = gethash(entity, contents);
       let old = assoc(attribute, attributes);
       if (old) rplacd(old, value);
       else {
         push(cons(attribute, value), attributes);
         puthash(entity, contents, attributes);}}
     
     // Return the value of an attribute for given entity.
     let DataBase::getValue(let entity, let attribute) {
       return cdr(assoc(attribute, gethash(entity, contents)));}
     

First notice the include command for Lpp.hh. To use Lpp a compilation unit needs to include the header file Lpp.hh when using let declarations.

Notice in the class definition the let type declarations. This is how members containing Lpp objects are always declared. Also notice that let type members can be easily combined with other types, in this case int.

In the data base accessor functions and in the following code that uses them the occurrences of Common Lisp function names such as car, cdr, cons, assoc, push, puthash, dolist etc. do exactly what you would expect them to do if you are familiar with Common Lisp.

Now we create a main program that populates the data base and prints a report on a family.

     
     /////////////////////////////////////////////////////////////////
     // Create and test a DataBase.
     
     main() {
       DataBase db = DataBase();
     
       db.addEntity(S(smith-family));
       db.setValue(S(smith-family), S(people),
                   list(S(joe), S(frank), S(mary)));
     
       db.addEntity(S(joe));
       db.setValue(S(joe), S(name), L("Joseph Clyde Smith"));
       db.setValue(S(joe), S(age), L(42));
       db.setValue(S(joe), S(siblings), list(S(frank), S(mary)));
     
       db.addEntity(S(frank));
       db.setValue(S(frank), S(name), L("Frank Bob Smith"));
       db.setValue(S(frank), S(age), L(32));
       db.setValue(S(frank), S(siblings), list(S(joe), S(mary)));
     
       db.addEntity(S(mary));
       db.setValue(S(mary), S(name), L("Mary Ann Smith"));
       db.setValue(S(mary), S(age), L(28));
       db.setValue(S(mary), S(brothers), list(S(joe), S(frank)));
     
       cout << "--- Report on Smith family ---" << endl;
       dolist(person, db.getValue(S(smith-family), S(people))) {
         cout << "Person: " << db.getValue(person, S(name)) << endl
              << "is " << db.getValue(person, S(age))
              << " years old" << endl;
         dolist(relation, list(S(siblings), S(brothers))) {
           let relatives = db.getValue(person, relation);
           if (relatives) {
             cout << "With " << relation << ": ";
             dolist(relative, relatives) cout << " " << relative;
             cout << endl;}}
         cout << endl;}}
     

Notice there are several occurrences of S() such as S(joe). This is the Lpp idiom for introducing symbols. Symbols are useful since they are very efficient and have universal identity. For example S(frank) refers to the same symbol frank every place that it is used in any program.

Also notice the occurrences of L(). This is the Lpp idiom for introducing C++ primitive types into the Lpp world of objects. L stands for Lpp conversion because in essence we are converting a C++ primitive value into an Lpp one. For example L(42) generates an Lpp Integer whose value is 42.

Finally notice that Lpp objects can be input and output to standard C++ streams. For example

     cout << " " << relative;
     

outputs the value of relative to the C++ standard output stream cout. The variable relative is dynamically bound to an Lpp object in the dolist macro.

Compiling the whole data base program above and running produces the following output:

     
     --- Report on Smith family ---
     Person: Joseph Clyde Smith
     is 42 years old
     With siblings:  frank mary
     
     Person: Frank Bob Smith
     is 32 years old
     With siblings:  joe mary
     
     Person: Mary Ann Smith
     is 28 years old
     With brothers:  joe frank