Dispatching from receive to a function

Juanjo Alvarez juanjux at thatwebmailofgoogleproperty.com
Mon Sep 27 11:46:18 PDT 2010


I'm new to the language so I don't know if this is horribly wrong on some 
levels, but it works:

-----------------------------

import std.variant;
import std.stdio;

class C
{
    bool test(int i, char c) { writeln("Hello from test1"); return true; }
    void test2(string v) { writeln("Hello from test2, ", v); }
}


void main()
{
    auto c = new C;
    Variant[string] holder = ["test": Variant(&c.test), "test2": Variant
(&c.test2)];
    receiver(holder);
}

void receiver(Variant[string] message) 
{
    // If you get the Variant template instantiation delegate 
    // signature wrong, it will
    // be detected at compile time!
    auto t = message["test"].get!(bool delegate(int, char));
    auto t2 = message["test2"].get!(void delegate(string));
    t(1, 'c');
    t2("foo");
}
--------------------------

Curiously if you create holder like this, it will give an arrayoutofbound 
error at runtime, I don't know if that is a bug:

void main()
{
   auto c = new C;
   Variant[string] holder;
   holder["test"] = Variant(&c.test);
   holder["test2"] = Variant(&c.test2);
}

On Mon, 27 Sep 2010 18:03:32 +0200, Johannes Pfau wrote:

> On 27.09.2010 15:36, Bob Cowdery wrote:
>>  Thanks. Do you know if the signature is a mandatory part. If I left
>>  the
>> signature out would it then only work with a delegate with no
>> parameters? If so I think I'm in the same state as my delegates will
>> not all have the same signature.
>> 
>> 
> Yep, the signature is mandatory. There is another, ugly, unsafe (it's
> safe, but you really have to be careful and write correct code) way:
> 
> Basically you cast away the delegates type information. You then store
> the delegate in an array. Later, you have to cast the delegate back to
> it's original type. The problem here is, that D doesn't provide enough
> runtime type information to know which type the delegate originally had,
> so _we_ have to store some type info _manually_. This can for example be
> done by storing both the delegate and our type info in a struct.
> 
> Here's an example how to do exactly that.
> 
> !!!Note: It's very important to always cast the delegate back to the
> _correct_ type before calling it, everything else leads to undefined
> behavior!!! So just setting CDelegate.Type to a wrong type can cause a
> disaster!
> 
> (Sorry about the bad variable names in the example. For better
> encapsulation most of the casts could be moved into the CDelegate struct
> by adding functions and constructors)
> 
---------------------------------------------------------------------------
> import std.stdio;
> 
> enum DelegateType
> {
>     A,
>     B,
>     C,
>     D
> }
> 
> struct CDelegate
> {
>     void delegate() del; //Exact type doesn't matter, all delegates have
> the same size
>     DelegateType Type;
> }
> 
> CDelegate[string] dict;
> 
> class C
> {
>     bool test(int i, char c) {return true;}
> }
> 
> class D
> {
>     int test(string s) {return 99;}
> }
> 
> void main()
> {
>     C c = new C();
>     D d = new D();
>     CDelegate custom;
> 
>     custom.del = cast(void delegate())&c.test; custom.Type =
>     DelegateType.C;
>     dict["c"] = custom;
> 
>     custom.del = cast(void delegate())&d.test; custom.Type =
>     DelegateType.D;
>     dict["d"] = custom;
> 
>     foreach(cdeleg; dict)
>     {
>         switch(cdeleg.Type)
>         {
>             case DelegateType.C:
>                 bool delegate(int i, char c) realdel = cast (bool
> delegate(int i, char c)) cdeleg.del;
>                 writeln(realdel(0, 'c'));
>                 break;
> 
>             case DelegateType.D:
>                 int delegate(string) realdel = cast (int
> delegate(string)) cdeleg.del;
>                 writeln(realdel("test"));
>                 break;
>         }
>     }
> }
> 
---------------------------------------------------------------------------



More information about the Digitalmars-d-learn mailing list