D (dlang) passing a lambda function as argument
Asked Answered
W

2

5

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

Walkin answered 4/10, 2019 at 6:46 Comment(0)
S
9

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.

Spectrograph answered 4/10, 2019 at 7:9 Comment(1)
Thanks you, yes the extra boolean slipped in there by mistake from my other code. I also missed passing an Event instance into the callback. Now I understand a bit more on how to pass functions in D (I'm mainly a JavaScript developer so tend to try things that way). This made it work fine: target.addEventListener( "load", (Event event) { writeln(variableFromParentScope, event); } );Walkin
F
3

target.addEventListener("load", (Event event) => { writeln(variableFromParentScope, event); }, true);

(Args) => {} is a lambda which returns a lambda.

Correct forms:

  • target.addEventListener("load", (Event event) { writeln(variableFromParentScope, event); }, true);

  • target.addEventListener("load", (Event event) => writeln(variableFromParentScope, event), true);

Fecundity answered 4/10, 2019 at 7:7 Comment(1)
Thanks, yes the last option works after I fixed the other bugs in my code as well.Walkin

© 2022 - 2024 — McMap. All rights reserved.