2005/5/10

     
 

Delegates

artefaktur

| 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.


Content of this chapter:

   DmiDelegates in ACDK
   Definition
   Create Delegates
     Create Delegate through implementing DmiDelegate interface
     Create Delegate from existent method
     Using delegates in CfgScript



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.

 DmiDelegates in ACDK

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.



 Definition

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.

 Create Delegates

 Create Delegate through implementing DmiDelegate interface



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.

 Create Delegate from existent method

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.

 Using delegates in CfgScript

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