www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - delegate issue

reply captaindet <2krnk gmx.net> writes:
hi,

i stumbled upon something weird - it looks like a bug to me but maybe it is a
"feature" that is unclear to me.

so i know i can declare function and delegate pointers at module level.
for function pointers, i can initialize with a lambda.
BUT for delegates i get an error - see below

i found out that using module static this(){...} provides a workaround, but why
is this necessary?

also, if there is a good reason after all then the error message should make
more sense.

/det

ps: i know there is a shorthand syntax for this.

----
module demo;

int function(int) fn = function int(int){ return 42; };
// ok

int delegate(int) dg = delegate int(int){ return 666; };
// demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

void main(){}
Jun 01 2014
next sibling parent reply "MrSmith" <mrsmith33 yandex.ru> writes:
On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but 
 maybe it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at 
 module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a 
 workaround, but why is this necessary?

 also, if there is a good reason after all then the error 
 message should make more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal 
 expression __dgliteral6

 void main(){}
You can't assign a delegate at compile time now. But you can do this in static constructor like this: int delegate(int) dg; static this() { dg = delegate int(int){ return 666; }; }
Jun 02 2014
parent reply captaindet <2krnk gmx.net> writes:
On 2014-06-02 08:03, MrSmith wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but maybe it is a
"feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a workaround, but
why is this necessary?

 also, if there is a good reason after all then the error message should make
more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

 void main(){}
You can't assign a delegate at compile time now. But you can do this in static constructor like this: int delegate(int) dg; static this() { dg = delegate int(int){ return 666; }; }
i knew about the static constructor, mentioned it in my OP ;) tried it in my project proper and got run-time cycle detected between modules ctors/dtors :( something new to figure out now. thanks, det
Jun 02 2014
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 02 Jun 2014 10:37:07 -0400, captaindet <2krnk gmx.net> wrote:

 On 2014-06-02 08:03, MrSmith wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but maybe  
 it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a  
 workaround, but why is this necessary?

 also, if there is a good reason after all then the error message  
 should make more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression  
 __dgliteral6

 void main(){}
You can't assign a delegate at compile time now. But you can do this in static constructor like this: int delegate(int) dg; static this() { dg = delegate int(int){ return 666; }; }
i knew about the static constructor, mentioned it in my OP ;) tried it in my project proper and got run-time cycle detected between modules ctors/dtors :( something new to figure out now.
FYI, the module ctor/dtor cycles thing is an interesting problem. When D decides to call module ctors or dtors, it wants to initialize them in an order where two initializations don't depend on one another. For instance: module a; import b; int x; static this() { x = b.x;} module b; import a; int x; static this() { x = a.x;} But of course, D does not know what exactly is done in module a, and module b. It could be: module a; import b; int x; static this() { x = b.x; } module b; import a; int x; static this() { x = 15;} Which could be perfectly legal, as long as module b is initialized before module a. But D doesn't have the information to sort this out. So at the moment, it has to assume the first situation, and reject the code. And it can only detect this at runtime, since we have no way to tell the linker to refuse to link this code. The typical solution is to put your static ctors into another module, which nothing will import (and therefore cannot be part of a cycle). A module with no static ctors/dtors will not be flagged as causing a problem. -Steve
Jun 02 2014
parent captaindet <2krnk gmx.net> writes:
On 2014-06-02 09:57, Steven Schveighoffer wrote:
 On Mon, 02 Jun 2014 10:37:07 -0400, captaindet <2krnk gmx.net> wrote:

 On 2014-06-02 08:03, MrSmith wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but
 maybe it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a workaround, but
why is this necessary?

 also, if there is a good reason after all then the error message should make
more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

 void main(){}
You can't assign a delegate at compile time now. But you can do this in static constructor like this: int delegate(int) dg; static this() { dg = delegate int(int){ return 666; }; }
i knew about the static constructor, mentioned it in my OP ;) tried it in my project proper and got run-time cycle detected between modules ctors/dtors :( something new to figure out now.
FYI, the module ctor/dtor cycles thing is an interesting problem. When D decides to call module ctors or dtors, it wants to initialize them in an order where two initializations don't depend on one another. For instance: module a; import b; int x; static this() { x = b.x;} module b; import a; int x; static this() { x = a.x;} But of course, D does not know what exactly is done in module a, and module b. It could be: module a; import b; int x; static this() { x = b.x; } module b; import a; int x; static this() { x = 15;} Which could be perfectly legal, as long as module b is initialized before module a. But D doesn't have the information to sort this out. So at the moment, it has to assume the first situation, and reject the code. And it can only detect this at runtime, since we have no way to tell the linker to refuse to link this code. The typical solution is to put your static ctors into another module, which nothing will import (and therefore cannot be part of a cycle). A module with no static ctors/dtors will not be flagged as causing a problem. -Steve
thanks a lot, steve! turned out - not surprisingly - that i would run into the ctor/dtor cycle issue whenever the user code module had a static constructor (even if not due to the delegate workaround mixin). i was able to refactor my package and after 'outsourcing' of the static constructor there, i can now use the mixed in static constructors in the user module to initialize the delegate with a default. not pretty, but it works! /det
Jun 02 2014
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but 
 maybe it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at 
 module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a 
 workaround, but why is this necessary?

 also, if there is a good reason after all then the error 
 message should make more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal 
 expression __dgliteral6

 void main(){}
This doesn't work, because a delegate needs a context it can capture, which is available only inside of a function. The workaround is either, as Mr Smith suggests, to use a static constructor, or you can use std.functional.toDelegate() (probably, didn't test).
Jun 02 2014
next sibling parent reply captaindet <2krnk gmx.net> writes:
On 2014-06-02 08:08, "Marc Schütz" <schuetzm gmx.net>" wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but
 maybe it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a
 workaround, but why is this necessary?

 also, if there is a good reason after all then the error message should make
more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

 void main(){}
This doesn't work, because a delegate needs a context it can capture, which is available only inside of a function.
so the real explanation is that a module as such has no context. much of the module design has the look and feel as if it were some sort of object, so this is a bit of a surprise to me. well, i learned something. thanks, det
Jun 02 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/02/2014 04:30 PM, captaindet wrote:

 This doesn't work, because a delegate needs a context it can capture,
 which is available only inside of a function.
so the real explanation is that a module as such has no context. much of the module design has the look and feel as if it were some sort of object, so this is a bit of a surprise to me. well, i learned something. thanks, det
The real explanation is that this doesn't work just because it doesn't work and it might/should work at some point in the future.
Jun 02 2014
prev sibling next sibling parent captaindet <2krnk gmx.net> writes:
On 2014-06-02 08:08, "Marc Schütz" <schuetzm gmx.net>" wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but maybe it is a
"feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a workaround, but
why is this necessary?

 also, if there is a good reason after all then the error message should make
more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

 void main(){}
This doesn't work, because a delegate needs a context it can capture, which is available only inside of a function. The workaround is either, as Mr Smith suggests, to use a static constructor, or you can use std.functional.toDelegate() (probably, didn't test).
i knew about the static constructor workaround (mentioned it in my OP). works in a simple case, but when i tried it in my project proper i hit a run-time error: cycle detected between modules ctors/dtors :( could be an unrelated, so far undetected bug, will look into it tonight. will try std.functional.toDelegate() as well, maybe it will do the trick. thanks, det
Jun 02 2014
prev sibling parent captaindet <2krnk gmx.net> writes:
On 2014-06-02 08:08, "Marc Schütz" <schuetzm gmx.net>" wrote:
 On Monday, 2 June 2014 at 06:56:54 UTC, captaindet wrote:
 hi,

 i stumbled upon something weird - it looks like a bug to me but
 maybe it is a "feature" that is unclear to me.

 so i know i can declare function and delegate pointers at module level.
 for function pointers, i can initialize with a lambda.
 BUT for delegates i get an error - see below

 i found out that using module static this(){...} provides a workaround, but
why is this necessary?

 also, if there is a good reason after all then the error message should make
more sense.

 /det

 ps: i know there is a shorthand syntax for this.

 ----
 module demo;

 int function(int) fn = function int(int){ return 42; };
 // ok

 int delegate(int) dg = delegate int(int){ return 666; };
 // demo.d(6): Error: non-constant nested delegate literal expression
__dgliteral6

 void main(){}
This doesn't work, because a delegate needs a context it can capture, which is available only inside of a function. The workaround is either, as Mr Smith suggests, to use a static constructor, or you can use std.functional.toDelegate() (probably, didn't test).
FWIW, tried toDelegate() and it does not work either: -------- module demo2; import std.functional : toDelegate; int function(int) fn = function int(int){ return 42; }; // ok int dg_def(int){ return 666; } int delegate(int) dg = toDelegate(&dg_def); // c:\D\DMD2\windows\bin\..\..\src\phobos\std\functional.d(758): Error: Cannot convert &int delegate(int a0) system to void* at compile time // demo2.d(8): called from here: toDelegate(& dg_def) void main(){}
Jun 02 2014