Search code examples
d

Writing functions conforming template defined function prototypes


To my sheer delight I discovered that D has made progress and now actually runs on Windows 64 bit. It even has a Visual Studio integration which seems to work as far as I can see after a few hours of playing with my new toy.

So, obviously I just started to play with D as a language and am a bloody newbie in D.

In the code below my goal was to define function prototypes in a template and then to write functions as sub-functions of main() which conform to those prototypes. But compiler complains and right now I cannot find out how to get it right (probably simple syntax problem).

The compiler errors I get are:

main.d(90): Error: function main.Actor!(int, int).Worker (Duration timeout, bool function(int) timeoutHandler, bool function(int, int) messageHandler, int context) is not callable using argument types ()

main.d(90): Error: function main.main.W1OnTimeout (int context) is not callable using argument types ()

main.d(90): Error: function main.main.W1OnMessage (int context, int message) is not callable using argument types ()

Building Debug\ConsoleApp1.exe failed!

import std.stdio;
import core.time;
import std.socket;
import std.concurrency;
import core.thread;

enum SystemMessage
{
    Shutdown,
    Terminate,
    Ping,
    Enable,
    Disable
}

template Actor(C,M) 
{
    // TimeoutHandler implementations always return true 
    // unless the worker shall terminate.
    alias TimeoutHandler = bool function(C);
    // MessageHandler implementations always return true 
    // unless the worker shall terminate.
    alias MessageHandler = bool function(C,M);

    void 
    Worker
        ( Duration timeout
        , TimeoutHandler timeoutHandler
        , MessageHandler messageHandler
        , C context
        )
    {
        bool running = true;
        bool enabled = true;
        while(running)
        {
            if( true == std.concurrency.receiveTimeout
                    (timeout,
                     (M message) 
                     {
                         if(enabled)
                         {
                            if(!messageHandler(context,message) )
                            {
                               running = false; 
                            }
                         }
                     },
                     (SystemMessage message)
                     {  
                         switch(message)
                         {
                             case SystemMessage.Shutdown: running = false; break;
                             case SystemMessage.Terminate: running = false; break;
                             case SystemMessage.Enable: enabled = true; break;
                             case SystemMessage.Disable: enabled = false; break;
                             case SystemMessage.Ping: /* TODO: supervisor... */; break;
                             default: break;
                         }
                     }
                     ))
            {
            }
            else
            {
                if(!timeoutHandler(context))
                {
                    running = false;
                }
            }
        }
    }
}

alias IntIntActor = Actor!(int,int);


int main(string[] argv)
{
    // The signatures of the next 2 functions conform to the function 
    // declarations, given in Actor template (IntIntActor). 
    // How to write them so it works?
    bool W1OnTimeout(int context)
    {
        writeln("W1OnTimeout()");
        return true;
    }
    bool W1OnMessage(int context,int message)
    {
        writefln("W1OnMessage: context = %d, message = %d", context, message);
        return true;
    }
    // Do I need some special syntax here? Like e.g. &W1OnTimeout ? Or a cast?
    auto w1 = spawn(IntIntActor.Worker,1000.msecs,W1OnTimeout,W1OnMessage,1);
    for(int i = 0; i < 10; i++)
    {
        send(w1,i);
    }
    Thread.sleep(5000.msecs);
    send(w1,SystemMessage.Shutdown);
    thread_joinAll();
    return 0;
}

Thanks for your help, in advance!


Solution

  • You pretty much gave the answer in your comment:

    // Do I need some special syntax here? Like e.g. &W1OnTimeout ? Or a cast?
    

    &W1OnTimeout is exactly it; also &IntIntActor.Worker and &W1OnMessage.

    It still won't compile, because &W1OnTimeout and &W1OnMessage are regarded as delegates, but Worker takes function pointers. Mark the nested functions static and it works:

    static bool W1OnTimeout(int context)
    {
        ...
    }
    static bool W1OnMessage(int context,int message)
    {
        ...
    }
    

    Alternatively, define them outside of main.