www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Order of static this() execution?

reply drathier <forum.dlang.org fi.fo> writes:
I'm having some trouble with the order in which `static this()` 
runs. This is the order defined in the source file, numbered for 
convenience:
```
logInfo("static this 1 initialModel");
logInfo("static this 1 initialModel done");
logInfo("static this 2 array branchfactor");
logInfo("static this 2 array branchfactor done");
logInfo("static this 3 array shiftstep");
logInfo("static this 3 array shiftstep done");
logInfo("static this 4 cmd none [template:%s]", typeid(msg));
logInfo("static this 4 cmd none [template:%s] done", typeid(msg));
logInfo("static this 5 main");
logInfo("static this 5 main done");
```
It's also the same order that `-vcg-ast` outputs. However, at 
runtime, I'm consistently seeing this order, where 5 and 4 are 
swapped:
```
[main(----) INF] static this 1 initialModel
[main(----) INF] static this 1 initialModel done
[main(----) INF] static this 2 array branchfactor
[main(----) INF] static this 2 array branchfactor done
[main(----) INF] static this 3 array shiftstep
[main(----) INF] static this 3 array shiftstep done
[main(----) INF] static this 5 main
[main(----) INF] static this 5 main done
[main(----) INF] static this 4 cmd none 
[template:delm.output.MsgT]
[main(----) INF] static this 4 cmd none 
[template:delm.output.MsgT] done
```
which leads to segfaults later on since static this 5 reads 
variables set up by static this 4.

The spec says that "The static constructors are run in lexical 
order" https://dlang.org/spec/module.html#staticorder . Is 
lexical order the same as the order things are defined in the 
source file?

I'm running `DMD64 D Compiler v2.090.1` on macos 10.14.6, in case 
that matters. I'm seeing the same issue with LDC `(1.19.0) based 
on DMD v2.089.1 and LLVM 9.0.0`
Feb 23 2020
parent reply Johan Engelen <j j.nl> writes:
On Sunday, 23 February 2020 at 09:59:45 UTC, drathier wrote:
 I'm having some trouble with the order in which `static this()` 
 runs. This is the order defined in the source file, numbered 
 for convenience:
To avoid confusion: you have all `static this()` in a single source file? Or across several source files? -Johan
Feb 23 2020
parent reply drathier <forum.dlang.org fi.fo> writes:
On Sunday, 23 February 2020 at 11:41:25 UTC, Johan Engelen wrote:
 On Sunday, 23 February 2020 at 09:59:45 UTC, drathier wrote:
 I'm having some trouble with the order in which `static 
 this()` runs. This is the order defined in the source file, 
 numbered for convenience:
To avoid confusion: you have all `static this()` in a single source file? Or across several source files? -Johan
They're all in a single source file. The `[template]` prints are inside templates, like this: ``` template none(msg) { T!(msg) none; static this() { none = ((std.functional.toDelegate(&batch!(msg) )))(X!(T!(msg) )); } } ``` The whole reason I have `static this()` is to avoid ctfe crashing from trying to run `toDelegate` at compile time: ``` std/functional.d(1501,22): Error: dummyDel.funcptr cannot be evaluated at compile time ```
Feb 23 2020
next sibling parent drathier <forum.dlang.org fi.fo> writes:
Well, like this, rather:
```
template none(msg) {
	T!(msg)  none;
	static this() {
		logInfo("static this 4 cmd none [template:%s]", typeid(msg));
		none = ((std.functional.toDelegate(&batch!(msg)
)))(X!(T!(msg) ));
		logInfo("static this 4 cmd none [template:%s] done", 
typeid(msg));
	}
}
```
Feb 23 2020
prev sibling next sibling parent reply Johan Engelen <j j.nl> writes:
On Sunday, 23 February 2020 at 11:55:11 UTC, drathier wrote:
 On Sunday, 23 February 2020 at 11:41:25 UTC, Johan Engelen 
 wrote:
 On Sunday, 23 February 2020 at 09:59:45 UTC, drathier wrote:
 I'm having some trouble with the order in which `static 
 this()` runs. This is the order defined in the source file, 
 numbered for convenience:
To avoid confusion: you have all `static this()` in a single source file? Or across several source files? -Johan
They're all in a single source file. The `[template]` prints are inside templates,
It's not clear from the language specification, but in this case with templates, I am not surprised that the order of execution is not the same as in the source file. Probably it does fit with the order in the source file if you take into account where the template is instantiated in that file (but you shouldn't depend on that). I strongly recommend not to depend on the order of multiple static this execution, by either rewriting things or by including some logic to make sure things are called in the right order (checking that something has already run, and running it if not, or cancel running it if it already ran) -Johan
Feb 23 2020
parent drathier <forum.dlang.org fi.fo> writes:
On Sunday, 23 February 2020 at 14:36:56 UTC, Johan Engelen wrote:
 It's not clear from the language specification, but in this 
 case with templates, I am not surprised that the order of 
 execution is not the same as in the source file. Probably it 
 does fit with the order in the source file if you take into 
 account where the template is instantiated in that file (but 
 you shouldn't depend on that).
 I strongly recommend not to depend on the order of multiple 
 static this execution, by either rewriting things or by 
 including some logic to make sure things are called in the 
 right order (checking that something has already run, and 
 running it if not, or cancel running it if it already ran)

 -Johan
This is generated code, so all defs are already topo-sorted. The template is instantiated before it's used, and in the .d.cg file it's also seemingly in the expected order. I'd be happy to put all initialisation code into a single static this(), but I'm not sure how to do that when templates get involved. Since it's generated code, the set of things that are easy/hard to do kinda swap around.
Feb 23 2020
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 2/23/20 6:55 AM, drathier wrote:
 On Sunday, 23 February 2020 at 11:41:25 UTC, Johan Engelen wrote:
 On Sunday, 23 February 2020 at 09:59:45 UTC, drathier wrote:
 I'm having some trouble with the order in which `static this()` runs. 
 This is the order defined in the source file, numbered for convenience:
To avoid confusion: you have all `static this()` in a single source file? Or across several source files? -Johan
They're all in a single source file. The `[template]` prints are inside templates, like this: ``` template none(msg) {     T!(msg)  none;     static this() {         none = ((std.functional.toDelegate(&batch!(msg) )))(X!(T!(msg) ));     } } ``` The whole reason I have `static this()` is to avoid ctfe crashing from trying to run `toDelegate` at compile time: ``` std/functional.d(1501,22): Error: dummyDel.funcptr cannot be evaluated at compile time ```
The static this is run in lexical order, but template static this are run as if they were stuck into the code at the first part they were instantiated. So for instance, if you have: template T() { int* T; static this() { T = new int; } } int x; static this() { x = *T!(); } The T instantiation comes AFTER the module-level static this. So it will run the module static this first, and then the T static this. How to fix this? I tried putting the template into a separate module. Technically, the static constructor will be inserted into the instantiating module. But it does seem to order it properly in that case. This is a limitation that I think D should be able to resolve. I'll file an issue report. -Steve
Feb 24 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 2/24/20 9:25 AM, Steven Schveighoffer wrote:
 I'll file an issue report.
https://issues.dlang.org/show_bug.cgi?id=20605 -Steve
Feb 24 2020