| DMI Basics | Features Profile | DMI Client Interface | ScriptVar | DMI Server | Using DMI in C++ | DMI with CfgScript | DMI Server Objects | Subclassing | Delegates |
A Delegate is a wrapper to a function, similar to function pointers.
Background
Delegates are often useful to implement some signal/slot pattern.
The are also very similar to C/C++ callback or function pointers.
The often used in following scenarios:
- connect one callback interface into a component, and don't want
to establish an interface type for this.
- connect very much callback interfaces into component.
- The callback type can have it's own type hierarchy.
- Dispatch events - which are not necessary associated with a type -
to a callback. A good example is the call back mechanism in ACDK WX.
In ACDK a delegate is a object interface acdk::lang::dmi::DmiDelegate which
is a wrapper to a interface, with only one method.
Different to a interface DmiDelegates are not typed, the call with the matching count and typed arguments
will be evaluated at runtime.
Here the very abstract definition of the DmiDelegate interface:
interface DmiDelegate
{
/** call the method with variable arguments */
virtual RDmiObject call(IN(RDmiObjectArray) args) = 0;
/** call the method with variable named arguments */
virtual RDmiObject call(IN(RDmiNamedArgArray) namedArgs) = 0;
}
|
Please refer to acdk::lang::dmi::DmiDelegate for C++ interface defintion.
In most cases only the virtual RDmiObject call(IN(RDmiObjectArray) args) will be invoked.
using namespace acdk::lang::dmi;
// C++
class MyDelegate
: extends Object
, implements DmiDelegate
{
// expect int as argument
// return int incremented with 1
virtual RDmiObject call(IN(RDmiObjectArray) args)
{
if (args->length() == 0)
{
return new DmiObject(ScriptVar()); // return void
}
return new DmiObject(inOf(args[i]->getIntVar() + 1));
}
virtual RDmiObject call(IN(RDmiNamedArgArray) namedArgs)
{
THROW1(UnsupportedOperationException, "MyDelegate::call(IN(RDmiNamedArgArray) namedArgs)")
return Nil;
}
};
// now DMI 'client' code
RDmiDelegate del = new MyDelegate();
int shouldBe3 = del->call(inOf(2))->getIntVar();
|
A acdk::lang::dmi::DmiObject is a equivalent to an any type.
It can hold and wraps any other ACDK type.
In most cases it is easier to create a DmiDelegate from an existent
ACDK Class.
Delegates can created from any public normal method indented if the method
is static or virtual or not using the acdk::lang::dmi::StdDmiDelegate class.
But the C++ class must support extended metainfo, so the dynamic
mapping from a untyped method signature to a native, typed C++ is possible.
// wrapp the virtual method println from the acdk::io::PrintWriter
// class into a Delegate
RDmiDelegate printer = new StdDmiDelegate(System::out, "println");
// just print something
printer->call(inOf("Hello"));
RDmiDelegate appender = new StdDmiDelegate(new StringBuffer(), "append");
appender->call(inOf(1));
appender->call(inOf("Hello"));
|
On misuse of a DmiDelegate - calling call with wrong number or types of the arguments -,
the call() may throw a DmiException.
A very powerful feature of Delegates is in CfgScript script.
Please refer to Delegates
and Lambda for the manifold possibilities
to use delegates in CfgScript
|