January 10, 2020
https://issues.dlang.org/show_bug.cgi?id=20498

          Issue ID: 20498
           Summary: A way to initialize a struct of delegates with no-op
                    stubs?
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: hsteoh@quickfur.ath.cx

Given a struct of delegates:

------
struct S {
    void delegate(int x) dg1;
    void delegate(float y) dg2;
    void delegate(int x, int y) dg3;
    ... // etc., many more delegates here
}
------

There ought to be an easy, hassle-free way of initializing the delegates to point to a no-op stub delegate that simply does nothing and returns. Currently, it's not possible to do this because dmd complains that lambdas or delegates of any kind of not readable at compile-time:

------
void dummy(int) {}
struct S {
    void function(int) f1 = &dummy; // OK: this works

    // But none of the following works (they all fail to compile):
    void delegate(int) dg1 = &dummy; // NG
    void delegate(int) dg2 = (int) {}; // NG
    void delegate(int) dg3 = (int) => dummy(0); // NG

    import std.functional;
    void delegate(int) dg4 = toDelegate((int) {}); // NG
    void delegate(int) dg5 = toDelegate(&dummy); // NG
}
------

The fact that the function pointer f1 can be initialized to point to a function implies that the address of a function can be used to initialize struct fields, even though it may not actually be bound until runtime.  By that logic, a dummy delegate that does nothing should also be assignable to the struct's .init value (the context pointer is ignored so it can simply be set to null).

Currently the only way to initialize the delegate fields is to do so at runtime by using a verbose, circuitous workaround:

------
struct S {
    void delegate(int) dg1;
    void delegate(float) dg2;
    void delegate(string) dg3;
    void delegate(int,int) dg4;
    void delegate(bool,dchar) dg5;
}

S s;
static this()
{
        static void nop(Args...)(Args) {}
        foreach (ref dg; s.tupleof)
        {
                import std.functional : toDelegate;
                import std.traits : Parameters;
                dg = toDelegate(&nop!(Parameters!(typeof(dg))));
        }
}
------

The template for `nop` is necessary because each struct field may have different parameters, requiring a function of a different signature, and putting inside the foreach loop doesn't work because the compiler complains that it's defined multiple times.

This seems extremely verbose and cumbersome for something so simple as setting the context pointer to null and .ptr to the address of a `ret` instruction.


Desired behaviour: there should be a simple, concise way to initialize a series of void delegates to point to a do-nothing stub.  This should be doable at compile-time, and should not require the above obscure verbiage (or equivalent).

Possible syntax:  perhaps something along these lines:

------
void delegate(int) = {};
void delegate(string,bool) = {};
... // and so on
------

or perhaps:

------
void delegate(int) = () {};
------

--