Lorien:InterfaceIntro

From Lorien Documentation
Jump to: navigation, search

Components in Lorien interact exclusively through formal interfaces. An interface is a typed collection of 1-N function prototypes, and a component may declare any number of provided and required interfaces. Each required interface of a component can be connected at runtime to the type-compatible provided interface of another component; this strict interface-based interaction between components is a key enabler of the dynamic loading and unloading of functionality at runtime.

To begin with you'll likely use the interfaces of Lorien's stock components without needing to develop new ones, but once you start building more advanced systems you'll no doubt need to design new interfaces to suit your needs.

As discussed in the component tutorial, interfaces are declared in either the provides or requires blocks, for example:

component requires{
   IMXRadio *radio;
   }

When a component with the above statement gets passed to Lorien's component compiler, the compiler recursively searches Lorien's interfaces/ directory for a header file containing the IMXRadio interface definition. The search is performed based on a header file naming convention.

In the case of IMXRadio this results in a recursive search for a header file imx_radio.h - essentially each "new word" upper-case character in the interface type name has an underscore inserted before it and then the whole thing is converted to lower-case. A new word is generally defined as an upper-case letter followed by a lower-case letter, unless the new word follows the first "I" of the type name, in which case no underscore is inserted. The compiler will warn you however if a header file with the expected name could not be found.

Let's now develop a simple new interface called IAverage which will be used in a component that supports data series averaging.

First we decide what functions we're going to provide with this interface. For this example we'll use functions addValue(), getAverage(), and clear().

Lorien interfaces are written using a simple interface definition syntax. It doesn't matter exactly where inside the interfaces/ directory we place our interface definition header file, since a recursive search is always performed for the first header file with the expected file name, but the interfaces/data/ directory seems like a good candidate here. If you prefer you can create new subdirectories to suit your needs.

So in interfaces/data/ we create a file iaverage.h and inside it place the interface definition:

interface IAverage{
   void addValue(int v);
   int getAverage();
   void clear();
   }

Back in our component code we can now define a component which provides this interface, for example:

component provides{
   IAverage;
   }

component state{
   int currentTotal;
   int currentValueCount;
   }

static void IAverage:addValue(int val)
   {
   currentTotal += val;
   currentValueCount ++;
   }

static int IAverage:getAverage()
   {
   return currentTotal / currentValueCount;
   }

static void IAverage:clear()
   {
   currentTotal = 0;
   currentValueCount = 0;
   }

int construct()
   {
   currentTotal = 0;
   currentValueCount = 0;
   return OK;
   }

int destruct()
   {
   return OK;
   }

And that's it - our new IAverage interface defined and implemented by a component. In another component we can declare a required interface of the type IAverage in the usual way:

component requires{
   IAverage *avg;
   }

And we can invoke its functions such as

avg -> addValue(9);

Interface usage in Lorien is type-checked both at compile-time and at the point of runtime composition to ensure type safety of component interaction at all times.

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox