Flip Programming Guide

 

Writing a Flip Class Part 1

This chapter and the next chapter will describe how to write a Flip Class as well as writing convention which should be followed to make it future proof.

In the following, we will show the step by step construction of an hypothetic MyClass class.

This chapter will assume that your company is called ACME making the application “Product”.

Declaring the Class

Every class managed by flip will need to inherit from ohm::flip::Object , so the first thing is to inherit from it. Since the base class needs a document to operate on, we will pass it to the constructor. It is important that every flip class constructor follows the same exact prototype.

We will also need to declare the class before we can use it, so that we will add a declare member.

#include "ohm/flip/Object.h"
class MyClass
:  public ohm::flip::Object
{
public:
   static void    declare ();
                  MyClass (ohm::flip::DocumentBase & document);
   virtual        ~MyClass () {}
   [...]
};

The function declare will declare this class to the Flip framework.

void  MyClass::declare ()
{
   using namespace ohm::flip;
   ClassDescription <MyClass>::use ().set_name ("acme.product.MyClass");   // 1.
   ClassDescManager::declare (ClassDescription <MyClass>::use ());         // 2.
}
  1. This line will link your class with a name given as the string. This string will be used when writing the document
  2. This line will add this class to the set of Flip managed classes

The constructor will pass the document to its base class.

MyClass::MyClass (ohm::flip::DocumentBase & document)
:  ohm::flip::Object (document)
{
}

Then we will add the class in the global declare function in fnc.cpp

void  declare ()
{
   flip::ClassDescManager::use_instance ().declare_basic_types ();
   
   MyClass::declare ();
   
   flip::EnumDescManager::use_instance ().post_check ();
   flip::ClassDescManager::use_instance ().post_check ();
}

Note:If you forget to declare a class, an assert will trigger on runtime, with a comment next to it to remind you to declare the class

Inheritance

The Flip framework has a limited while being sufficient support for inheritance : It does not support multiple inheritance.

To make MySubClass inherit from MyClass we will make it inherit in the C++ code and declare the inheritience in the declare function.

class MySubClass
:  public MyClass
{
public:
   static void    declare ();
   [...]
};

The function declare will declare this class to the Flip framework.

void  MySubClass::declare ()
{
   using namespace ohm::flip;
   ClassDescription <MySubClass>::use ().set_name ("acme.product.MySubClass");
   ClassDescription <MySubClass>::use ().inherit <MyClass> ();
   ClassDescManager::declare (ClassDescription <MySubClass>::use ());
}

Then we will add the class in the global declare function in fnc.cpp and make sure that the base class is declared before our class.

void  declare ()
{
   flip::ClassDescManager::use_instance ().declare_basic_types ();
   
   MyClass::declare ();
   MySubClass::declare ();
   
   flip::EnumDescManager::use_instance ().post_check ();
   flip::ClassDescManager::use_instance ().post_check ();
}

Adding Flip Members

Every class managed by flip may contain an illimited number of either Flip basic types or your own custom Flip classes.

Flip offers, three categories of basic types :

Value Types

Value types are limited to 3 types :

ohm::flip::Bool will hold a boolean value, ohm::flip::Int64 will hold a 64 bits integer value and ohm::flip::Float64 will hold a 64 bits floating point value.

They are defined respectively in ohm/flip/Bool.h , ohm/flip/Int64.h and ohm/flip/Float64.h

Enumeration Types

The ohm::flip::Enum type will hold an enumeration based on a C++ enum.

It is defined in ohm/flip/Enum.h

Opaque Data Type

The ohm::flip::Blob type will hold an opaque dynamic-sized blob of data.

It is defined in ohm/flip/Blob.h

Containers

Container types are limited to 2 types :

ohm::flip::Array will hold an explicit ordered list of object. ohm::flip::Colletion will hold an implicit orderer list or an unordered list of object.

They are defined respectively in ohm/flip/Array.h and ohm/flip/Colletion.h

Reference Type

Flip offers a Reference type, named ohm::flip::ObjectRef that allows to reference another Flip object in the model tree.

Signaling Type

The Flip framework contains one signaling type, named ohm::flip::Cue that allows to signal other users with data that is not persistent (that is not written in the document)

It is defined in ohm/flip/Cue.h

Using Types

Adding a Flip member consists of adding it to the Flip class and declaring it to the Flip framework.

#include "ohm/flip/Object.h"
#include "ohm/flip/Bool.h"
#include "ohm/flip/Int64.h"
#include "ohm/flip/Float64.h"
#include "ohm/flip/Enum.h"
#include "ohm/flip/Array.h"
#include "ohm/flip/Collection.h"
#include "ohm/flip/Cue.h"
class MyClass
:  public ohm::flip::Object
{
public:
   enum MyEnum
   {
                        MyEnum_FOO = 0,
                        MyEnum_BAR,
      
                        MyEnum_NBR_ELT
   }
   static void          declare ();
                        MyClass (ohm::flip::DocumentBase & document);
   virtual              ~MyClass () {}
private:
   ohm::flip::Bool      _my_bool;
   ohm::flip::Int64     _my_int;
   ohm::flip::Float64   _my_float;
   ohm::flip::Enum <MyEnum, MyEnum_FOO, MyEnum_NBR_ELT>
                        _my_enum;
   ohm::flip::Blob      _my_blob;
   ohm::flip::Array <MyElementClass>
                        _my_array;
   ohm::flip::Collection <MyElementClass>
                        _my_collection;
   ohm::flip::Cue       _my_cue;
};

The function declare will declare those members to the Flip framework.

void  MyClass::declare ()
{
   using namespace ohm::flip;
   EnumDescription <MyEnum>::use ().set_name ("acme.product.MyClass.MyEnum");
   EnumDescription <MyEnum>::use ().push_enum_desc (MyEnum_FOO, "MyEnum_FOO");
   EnumDescription <MyEnum>::use ().push_enum_desc (MyEnum_BAR, "MyEnum_BAR");
   EnumDescManager::declare (EnumDescription <MyEnum>::use ());
   ClassDescription <MyClass>::use ().set_name ("acme.product.MyClass");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_bool, "_my_bool");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_int, "_my_int");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_float, "_my_float");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_enum, "_my_enum");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_blob, "_my_blob");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_array, "_my_array");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_collection, "_my_collection");
   ClassDescription <MyClass>::use ().push_var_desc (&MyClass::_my_cue, "_my_cue");
   ClassDescManager::declare (ClassDescription <MyClass>::use ());
}

In the above code, the enum is declared first before the member using the enum is declared. The code will assign a name to the enums and members and will be used when saving the document.

The constructor will pass the document to its members.

MyClass::MyClass (ohm::flip::DocumentBase & document)
:  ohm::flip::Object (document)
,  _my_bool (document)
,  _my_int (document)
,  _my_float (document)
,  _my_enum (document)
,  _my_blob (document)
,  _my_array (document)
,  _my_collection (document)
,  _my_cue (document)
{
}

Now that we have declared the model, the next step will be to manipulate it, which we will show in the next chapter. However all the above code is essentially what is used by the server.