Next: , Previous: , Up: Code Integration   [Contents][Index]


8.2 Foreign Component

We already saw how to connect code directly to event slots in the interface. If we desire to encapsulate this code, we can use a component without a behavior8 to achieve this. The code generator will generate a similar C++ representation for components with and without behavior. The only difference is that a component without behavior declares pure virtual functions which must be implemented by a struct of class which inherits from the generated C++ representation. Note that this approach is not suitable to wrap a Dezyne component or system, since it would add the Dezyne semantic constraints via the runtime library a second time. The derived struct or class must have the same name as the component in Dezyne. To avoid a naming conflict, the generated representation with the same name as the Dezyne component is placed into the skel9 namespace.

It may not be obvious that we may run into a conflict when we put our foreign component in a file with the same name as the component. The reasons for this are as follows. Names introduced in Dezyne are also used by the generated code to refer to component representations. If a component is not defined locally Dezyne import is mapped to a #include. This means that the actual implementation of a foreign component must be in a file with the name derived from the component name. Therefore the component representation in the skel namespace is not written to the same file, the code generator simply refuses this. The solution is to put foreign component definitions into another file, for instance in the file of the system instantiating the component.

When implementing the foreign component the compiler must also be able to see the representation in the skel namespace. The code generator makes sure that the actual implementation inheriting the skel representation is included directly after it. Therefore we do not have to include anything into the header file of our foreign implementation. However, if we put the actual definition into a separate source file, we must include both the header file of the actual foreign component as well as the header file declaring the skel representation.

An example will help clarifying:

// hello_foreign.dzn

interface ihello
{
  in void hello ();
  out void world ();

  behavior
  {
    on hello: world;
  }
}

component foreign
{
  provides ihello p;
}

component hello
{
  provides ihello p;
  requires ihello r;

  behavior
  {
    on p.hello (): r.hello ();
    on r.world (): p.world ();
  }
}

component hello_foreign
{
  provides ihello p;

  system
  {
    p <=> h.p;
    hello h;
    h.r <=> f.p;
    foreign f;
  }
}

// end of hello_foreign.dzn

Here we see an interface ihello, a foreign component, a regular component hello and a system hello_foreign being defined.

For C++ the code generator produces a hello_foreign.hh and a hello_foreign.cc file. Since hello_foreign instantiates the component foreign, it will #include a file called foreign.hh. The contents of this file might look something like this:

#ifndef FOREIGN_HH
#define FOREIGN_HH

struct foreign: public skel::foreign
{
  foreign (const dzn::locator &locator)
    : skel::foreign (locator)
  {}
  void p_hello ()
  {
    p.out.world ();
  }
};

#endif

Note the absence of an #include statement.

If we want to move all member function definitions from the header file to a source file, we might write foreign.cc like this.

#include "hello_foreign.hh"

foreign::foreign (const dzn::locator &locator)
  : skel::foreign (locator)
{}

void foreign::p_hello ()
{
  p.out.world ();
}

Note the presence of #include "hello_foreign.hh" and remember this already includes foreign.hh.


Footnotes

(8)

A foreign component is a component without behavior in Dezyne.

(9)

skel is short for skeleton.


Next: Thread-safe Shell, Previous: Integrating C++ Code, Up: Code Integration   [Contents][Index]