digitalmars.D - Initializing a table of delegates with no-op stubs
- H. S. Teoh (40/40) Jan 09 2020 I have a struct containing a bunch of delegates:
- Steven Schveighoffer (12/58) Jan 09 2020 I thought this might work, but toDelegate seems to not be usable at
- Arine (7/7) Jan 10 2020 This works too:
- H. S. Teoh (6/15) Jan 10 2020 [...]
- Rainer Schuetze (9/21) Jan 11 2020 This seems to work:
- Steven Schveighoffer (24/52) Jan 11 2020 No need for the function call
- Arine (11/13) Jan 11 2020 I think there's probably a check that just stops delegates
- H. S. Teoh (17/25) Jan 13 2020 [...]
- Rainer Schuetze (3/30) Jan 13 2020 I think it's a bug in the compiler. If you can assign an enum value, why
- Timon Gehr (2/4) Jan 13 2020 Related: https://issues.dlang.org/show_bug.cgi?id=12288
- H. S. Teoh (7/28) Jan 20 2020 Added info to the bug:
I have a struct containing a bunch of delegates: struct S { void delegate(int blah) dg1; void delegate(string blah) dg2; void delegate(int x, int y) dg3; ... // lots of these } How do I initialize them to no-op stubs? I've tried all sorts of ways but couldn't get it to work. It's easy to do with a *function pointer* -- just declare a dummy no-op function with the right signature and take its address: void dummy(int) {} struct S { void function(int) f1 = &dummy; // OK // But it doesn't work with delegates, no way, no how: void delegate(int) dg1 = &dummy; // NG void delegate(int) dg2 = (int) {}; // NG void delegate(int) dg3 = (int) => dummy(0); // NG } I even tried to make a function that returns an empty delegate, but when I try to assign that to the struct member the compiler complains that it's a non-constant expression. Seriously, why is it so hard to initialize a delegate field to point to a 'ret' instruction?! That's all I need. It doesn't even need a context pointer, since it's supposed to do nothing. Since it's possible to initialize struct fields to function pointers, surely it can't be *that* hard to also initialize them to point to empty delegates? The only success I have is to defer to runtime, and even then it involves a whole mouthful of periphrasis: S s; foreach (ref dg; s.tupleof) { import std.traits : Parameters; void impl(size_t i)(Parameters!(typeof(dg))) {} dg = &impl; } Am I missing something obvious?? T -- Never ascribe to malice that which is adequately explained by incompetence. -- Napoleon Bonaparte
Jan 09 2020
On 1/9/20 5:02 PM, H. S. Teoh wrote:I have a struct containing a bunch of delegates: struct S { void delegate(int blah) dg1; void delegate(string blah) dg2; void delegate(int x, int y) dg3; ... // lots of these } How do I initialize them to no-op stubs? I've tried all sorts of ways but couldn't get it to work. It's easy to do with a *function pointer* -- just declare a dummy no-op function with the right signature and take its address: void dummy(int) {} struct S { void function(int) f1 = &dummy; // OK // But it doesn't work with delegates, no way, no how: void delegate(int) dg1 = &dummy; // NG void delegate(int) dg2 = (int) {}; // NG void delegate(int) dg3 = (int) => dummy(0); // NG }I thought this might work, but toDelegate seems to not be usable at compile time: void delegate(int) dg1 = toDelegate((int) {});I even tried to make a function that returns an empty delegate, but when I try to assign that to the struct member the compiler complains that it's a non-constant expression. Seriously, why is it so hard to initialize a delegate field to point to a 'ret' instruction?! That's all I need. It doesn't even need a context pointer, since it's supposed to do nothing. Since it's possible to initialize struct fields to function pointers, surely it can't be *that* hard to also initialize them to point to empty delegates? The only success I have is to defer to runtime, and even then it involves a whole mouthful of periphrasis: S s; foreach (ref dg; s.tupleof) { import std.traits : Parameters; void impl(size_t i)(Parameters!(typeof(dg))) {} dg = &impl; } Am I missing something obvious??toDelegate should work at runtime, but you'd have to know the types anyway, so your runtime thing is probably just as verbose using that. I'd recommend still using static void impl, and using toDelegate to avoid any closures. It would be useful if toDelegate either worked at compile time, or the compiler allowed auto conversion to delegates (as it's always possible, a la toDelegate). -Steve
Jan 09 2020
This works too: struct S { void function(int) f1 = (int) { }; // OK } Which makes me think, it isn't allowing it because of the context pointer. But if that context pointer is null, it should work. File a bug report and hope it gets fixed soon™?
Jan 10 2020
On Fri, Jan 10, 2020 at 05:59:53PM +0000, Arine via Digitalmars-d wrote:This works too: struct S { void function(int) f1 = (int) { }; // OK } Which makes me think, it isn't allowing it because of the context pointer. But if that context pointer is null, it should work. File a bug report and hope it gets fixed soon™?[...] https://issues.dlang.org/show_bug.cgi?id=20498 T -- English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
Jan 10 2020
On 09/01/2020 23:02, H. S. Teoh wrote:void dummy(int) {} struct S { void function(int) f1 = &dummy; // OK // But it doesn't work with delegates, no way, no how: void delegate(int) dg1 = &dummy; // NG void delegate(int) dg2 = (int) {}; // NG void delegate(int) dg3 = (int) => dummy(0); // NG }[...]Am I missing something obvious??This seems to work: void noop(int) {} enum void delegate(int) dg_noop = (int x){ noop(x); }; struct S { void delegate(int) dg = dg_noop; }
Jan 11 2020
On 1/11/20 4:40 AM, Rainer Schuetze wrote:On 09/01/2020 23:02, H. S. Teoh wrote:No need for the function call enum void delegate(int) dg_noop = (int x) {};void dummy(int) {} struct S { void function(int) f1 = &dummy; // OK // But it doesn't work with delegates, no way, no how: void delegate(int) dg1 = &dummy; // NG void delegate(int) dg2 = (int) {}; // NG void delegate(int) dg3 = (int) => dummy(0); // NG }[...]Am I missing something obvious??This seems to work: void noop(int) {} enum void delegate(int) dg_noop = (int x){ noop(x); };struct S { void delegate(int) dg = dg_noop; }OK, so I think what is happening here is that a delegate defined inside a struct is going to use a struct `this` reference as the context pointer, and I get a weird message (why didn't you show this in the first place?): Error: delegate onlineapp.S.__lambda2 cannot be struct members It could be a possibility that if you use a delegate as an initializer outside a member function context, then it becomes like a global delegate? In any case, here is a solution that works and is pretty reasonable: enum void delegate(T) dummydg(T...) = (T params) {}; struct S { void delegate(int) dg = dummydg!int; void delegate(string, int) dg2 = dummydg!(string, int); } void main() { S s; s.dg(1); s.dg2("hi", 1); } -Steve
Jan 11 2020
On Saturday, 11 January 2020 at 14:51:24 UTC, Steven Schveighoffer wrote:In any case, here is a solution that works and is pretty reasonable:I think there's probably a check that just stops delegates completely from being default initialized in structs. struct S { void delegate(int) dg2 = cast(void delegate(int)) function (int x) {}; } That has the same error message. Just cause there's a (hacky) workaround, doesn't mean the most intuitive way to do it shouldn't be fixed.
Jan 11 2020
On Sat, Jan 11, 2020 at 09:51:24AM -0500, Steven Schveighoffer via Digitalmars-d wrote:On 1/11/20 4:40 AM, Rainer Schuetze wrote:[...][...] Mmm, very nice! Kind of a weird paraphrasis, but at least it works. To minimize hassle, I turned it into a template: enum void delegate(Args) doNothing(Args...) = (Args args) {}; struct S { void delegate(int x) dg1 = doNothing!(int); void delegate(float y) dg2 = doNothing!(float); void delegate(int x, int y) dg3 = doNothing!(int,int); } Do you think the first line is worth an addition to Phobos, maybe alongside toDelegate? It's non-obvious enough that it might save a newbie (or a not-so-newbie like myself :-P) a lot of headache. T -- Political correctness: socially-sanctioned hypocrisy.void noop(int) {} enum void delegate(int) dg_noop = (int x){ noop(x); };No need for the function call enum void delegate(int) dg_noop = (int x) {};
Jan 13 2020
On 13/01/2020 19:06, H. S. Teoh wrote:On Sat, Jan 11, 2020 at 09:51:24AM -0500, Steven Schveighoffer via Digitalmars-d wrote:I think it's a bug in the compiler. If you can assign an enum value, why should the value itself not be good enough aswell?On 1/11/20 4:40 AM, Rainer Schuetze wrote:[...][...] Mmm, very nice! Kind of a weird paraphrasis, but at least it works. To minimize hassle, I turned it into a template: enum void delegate(Args) doNothing(Args...) = (Args args) {}; struct S { void delegate(int x) dg1 = doNothing!(int); void delegate(float y) dg2 = doNothing!(float); void delegate(int x, int y) dg3 = doNothing!(int,int); } Do you think the first line is worth an addition to Phobos, maybe alongside toDelegate? It's non-obvious enough that it might save a newbie (or a not-so-newbie like myself :-P) a lot of headache.void noop(int) {} enum void delegate(int) dg_noop = (int x){ noop(x); };No need for the function call enum void delegate(int) dg_noop = (int x) {};
Jan 13 2020
On 13.01.20 23:43, Rainer Schuetze wrote:I think it's a bug in the compiler. If you can assign an enum value, why should the value itself not be good enough aswell?Related: https://issues.dlang.org/show_bug.cgi?id=12288
Jan 13 2020
On Mon, Jan 13, 2020 at 11:43:22PM +0100, Rainer Schuetze via Digitalmars-d wrote:On 13/01/2020 19:06, H. S. Teoh wrote:[.[..]Added info to the bug: https://issues.dlang.org/show_bug.cgi?id=20498 T -- Why is it that all of the instruments seeking intelligent life in the universe are pointed away from Earth? -- Michael BeiblMmm, very nice! Kind of a weird paraphrasis, but at least it works. To minimize hassle, I turned it into a template: enum void delegate(Args) doNothing(Args...) = (Args args) {}; struct S { void delegate(int x) dg1 = doNothing!(int); void delegate(float y) dg2 = doNothing!(float); void delegate(int x, int y) dg3 = doNothing!(int,int); } Do you think the first line is worth an addition to Phobos, maybe alongside toDelegate? It's non-obvious enough that it might save a newbie (or a not-so-newbie like myself :-P) a lot of headache.I think it's a bug in the compiler. If you can assign an enum value, why should the value itself not be good enough aswell?
Jan 20 2020