Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D (dlang) passing a lambda function as argument

With D, how can I pass a function (possibly reference to a function) as an argument to be executed inside other function?

import std.stdio : writeln;

class Event {}

class EventTarget
{
    void addEventListener(string eventName, void delegate(Event event) callback)
    {
        // TODO: add to slice to execute later, for now execute directly
        callback();
    }
}

void main()
{
    auto variableFromParentScope = "lorem ipsum";
    auto target = new EventTarget();
    target.addEventListener("load", (Event event) => { writeln(variableFromParentScope, event); }, true);
}

Gives me the error:

onlineapp.d(10): Error: delegate callback(Event event) is not callable using argument types ()
onlineapp.d(10):        missing argument for parameter #1: Event event
onlineapp.d(18): Error: function onlineapp.EventTarget.addEventListener(string eventName, void delegate(Event event) callback) is not callable using argument types (string, void delegate() @system delegate(Event event) pure nothrow @safe, bool)
onlineapp.d(18):        cannot pass argument __lambda1 of type void delegate() @system delegate(Event event) pure nothrow @safe to parameter void delegate(Event event) callback

I have set up the example here: https://run.dlang.io/is/FnQoId


SOLUTION, With the help from the answers I fixed it like this:

import std.stdio : writeln;

class Event {}

class EventTarget
{
    void addEventListener(string eventName, void delegate(Event event) callback)
    {
        // TODO: add to slice to execute later, for now execute directly
        callback(new Event());
    }
}

void main()
{
    auto variableFromParentScope = "lorem ipsum";
    auto target = new EventTarget();
    target.addEventListener(
        "load", 
        (Event event) {
            writeln(variableFromParentScope, event);
        }
    );
}

Working example: https://run.dlang.io/is/6aDRoU

like image 842
tirithen Avatar asked Oct 04 '19 06:10

tirithen


1 Answers

You are using the wrong syntax for the delegate, as you can also see in the error message it doesn't have the expected type.

To explain further, I will show you how it changes if you extend it to the longer form of a delegate instead of using the shorthand =>:

(Event event) => { writeln(variableFromParentScope, event); }

becomes

(Event event) { return { writeln(variableFromParentScope, event); }; }

As you can see you are returning a delegate with no parameters inside your actual delegate. If you remove the =>, your delegate will work as expected.

Alternative valid forms for your delegate parameter would be:

(event) { ... }
delegate (Event event) { ... }
delegate (event) { ... }
&someMemberMethod // some object member method taking in Event as first parameter
toDelegate(&someGlobalFunction) // from std.functional

Only if you want to return something you use the => arrow. A use-case for () => { something } would be a delegate returning a delegate (like a delegate generating delegates for a given input)

But also wrong in your question is that you are calling that function with a , true in the calling parameters, which makes the error message very confused, and that you aren't passing an event parameter to the callback, which would be another error in the code snippet.

like image 104
WebFreak001 Avatar answered Oct 24 '22 04:10

WebFreak001