Thread overview
CTFE in imported static initializers
May 14, 2019
Stefan Koch
May 14, 2019
Bastiaan Veelo
May 14, 2019
kinke
May 13, 2019
I have just discovered an interesting behavior, and I'm wondering if this behavior is intentional or even necessary.

Let's say I have this module called mod2.d:

module mod2;

string buildModData()
{
    string result;
    foreach(i; 0 .. 10000)
        result = result ~ "lots and lots and lots of data";
    return result;
}

static moddata = buildModData();

OK, so building this with -c on my system takes about 1 second of time:

Stevens-MacBook-Pro:ctfetest steves$ time dmd -c mod2.d

real	0m0.994s
user	0m0.434s
sys	0m0.554s


Now, I make a new module mod1.d:

module mod1;

import mod2;

And...

Stevens-MacBook-Pro:ctfetest steves$ time dmd -c mod1.d

real	0m0.993s
user	0m0.435s
sys	0m0.553s


This is because the CTFE engine is re-evaluating the static initializer, and then basically, throwing it away.

Why? I can't even use it at compile time...

pragma(msg, moddata.length);

mod1.d(5): Error: static variable moddata cannot be read at compile time
mod1.d(5):        while evaluating pragma(msg, moddata.length)

Why would the compiler re-run CTFE stuff that has already been run, or that at least it has no intention of using at compile time?

I found this because I'm trying to fix the import std.path issue (with -unittest on). I found this kind of stuff happening in phobos.

Does anyone have a good answer for why this should happen, or should I file a bug?

-Steve
May 14, 2019
On 5/13/19 9:39 PM, Steven Schveighoffer wrote:

> Does anyone have a good answer for why this should happen, or should I file a bug?


It's been mentioned to me that type inference is used here. However, one could argue that the CTFE doesn't need to complete in order to infer the type, the function is not a template or auto function.

In addition, if I change the declaration to:

static string moddata = ...;

It still takes 1 second to compile mod1.

-Steve
May 14, 2019
On Monday, 13 May 2019 at 20:39:57 UTC, Steven Schveighoffer wrote:
> Why? I can't even use it at compile time...
>
> pragma(msg, moddata.length);

Is that a good test or "usable at compile time", though? Isn't pragma(msg) done at an earlier stage than CTFE? I think that was the argument for ctfeWriteln.

(We both know that I'm out of my league here, but anyway :))

Bastiaan.
May 14, 2019
On Tuesday, 14 May 2019 at 08:26:41 UTC, Steven Schveighoffer wrote:
> On 5/13/19 9:39 PM, Steven Schveighoffer wrote:
>
>> Does anyone have a good answer for why this should happen, or should I file a bug?
>
>
> It's been mentioned to me that type inference is used here. However, one could argue that the CTFE doesn't need to complete in order to infer the type, the function is not a template or auto function.
>
> In addition, if I change the declaration to:
>
> static string moddata = ...;
>
> It still takes 1 second to compile mod1.
>
> -Steve

try changing it to static immutable.
May 14, 2019
On 5/14/19 10:30 AM, Stefan Koch wrote:
> On Tuesday, 14 May 2019 at 08:26:41 UTC, Steven Schveighoffer wrote:
>> On 5/13/19 9:39 PM, Steven Schveighoffer wrote:
>>
>>> Does anyone have a good answer for why this should happen, or should I file a bug?
>>
>>
>> It's been mentioned to me that type inference is used here. However, one could argue that the CTFE doesn't need to complete in order to infer the type, the function is not a template or auto function.
>>
>> In addition, if I change the declaration to:
>>
>> static string moddata = ...;
>>
>> It still takes 1 second to compile mod1.
>>
> 
> try changing it to static immutable.

Still 1 second.

-Steve
May 14, 2019
On 5/14/19 10:25 AM, Bastiaan Veelo wrote:
> On Monday, 13 May 2019 at 20:39:57 UTC, Steven Schveighoffer wrote:
>> Why? I can't even use it at compile time...
>>
>> pragma(msg, moddata.length);
> 
> Is that a good test or "usable at compile time", though? Isn't pragma(msg) done at an earlier stage than CTFE? I think that was the argument for ctfeWriteln.

No, pragma(msg) can happen after CTFE:

pragma(msg, buildModData()[0 .. 100]);

> 
> (We both know that I'm out of my league here, but anyway :))

Well, this is the learn forum, I too am out of my league when it comes to what's valid here ;)

-Steve
May 14, 2019
On 5/13/19 9:39 PM, Steven Schveighoffer wrote:
> I have just discovered an interesting behavior, and I'm wondering if this behavior is intentional or even necessary.
> 
> Let's say I have this module called mod2.d:
> 
> module mod2;
> 
> string buildModData()
> {
>      string result;
>      foreach(i; 0 .. 10000)
>          result = result ~ "lots and lots and lots of data";
>      return result;
> }
> 
> static moddata = buildModData();

A workaround found by Jonathan Davis:

string moddata() {
   static result = buildModData();
   return result;
}

-Steve
May 14, 2019
On Tuesday, 14 May 2019 at 10:21:23 UTC, Steven Schveighoffer wrote:
> I too am out of my league when it comes to what's valid here ;)

Valid or not, 1 second is ridiculous, please file a bug. For an importing module, it's just an external TLS global. As you mentioned, type inference shouldn't need a full evaluation of the initializer, but that's not the problem, as `static string moddata = buildModData();` doesn't improve anything.
May 14, 2019
On 5/14/19 8:06 PM, kinke wrote:
> On Tuesday, 14 May 2019 at 10:21:23 UTC, Steven Schveighoffer wrote:
>> I too am out of my league when it comes to what's valid here ;)
> 
> Valid or not, 1 second is ridiculous, please file a bug. For an importing module, it's just an external TLS global. As you mentioned, type inference shouldn't need a full evaluation of the initializer, but that's not the problem, as `static string moddata = buildModData();` doesn't improve anything.

OK, now that I have a compiler developer agreeing, I feel more comfortable filing ;)

-Steve
May 15, 2019
On 5/14/19 10:41 PM, Steven Schveighoffer wrote:

> OK, now that I have a compiler developer agreeing, I feel more comfortable filing ;)


https://issues.dlang.org/show_bug.cgi?id=19874

-Steve