Thread overview
Order of static this() execution?
Feb 23, 2020
drathier
Feb 23, 2020
Johan Engelen
Feb 23, 2020
drathier
Feb 23, 2020
drathier
Feb 23, 2020
Johan Engelen
Feb 23, 2020
drathier
February 23, 2020
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`
February 23, 2020
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

February 23, 2020
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
```
February 23, 2020
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));
	}
}
```

February 23, 2020
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

February 23, 2020
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.
February 24, 2020
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
February 24, 2020
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