"temporary" templates

Steven Schveighoffer schveiguy at gmail.com
Wed Nov 27 16:15:48 UTC 2019


On 11/27/19 3:03 AM, Paul Backus wrote:
> On Tuesday, 26 November 2019 at 19:11:14 UTC, Steven Schveighoffer wrote:
>> On 11/26/19 1:59 PM, Paul Backus wrote:
>>>
>>> This will cause compilation to become non-deterministic, since the 
>>> result of template evaluation can depend on the order in which 
>>> declarations are semantically analyzed:
>>>
>>> enum hasFoo(T) = __traits(hasMember, T, "foo");
>>>
>>> struct S {
>>>      // hasFoo!S is instantiated before the mixin is processed
>>>      static if (hasFoo!S) {}
>>>      mixin("int foo;");
>>> }
>>>
>>> pragma(msg, hasFoo!S); // false
>>>
>>> If for some reason the "innards" of `hasFoo!S` are discarded due to 
>>> memory pressure, reconstructing them later will give a different result.
>>
>> But that's an evaluation order issue. hasFoo should be true in both 
>> cases. Otherwise, you have the paradox:
>>
>> static assert(hasFoo!S == __traits(hasMember, T, "foo"))
> 
> There are situations where a particular evaluation order is forced. For 
> example:
> 
> enum hasFoo(T) == __traits(hasMember, T, "foo");
> 
> struct S {
>      static if (!hasFoo!S) {
>          int foo;
>      }
> }
> 
> static assert(hasFoo!S == __traits(hasMember, S, "foo")); // fails
> 
> The condition of the static if *must* be evaluated before the body, so 
> there is no way to have hasFoo!S evaluate to the same thing in both 
> places without causing a paradox. Note that this is *not* an accident of 
> the current compiler implementation; it follows directly from the 
> definition of `static if` in the language spec.

OK, this is more of a correct argument since obviously hasFoo must be 
false to add foo, but then it should be true after that. So it's still 
not ideal, and still a paradox.

What I am proposing is that you can mark items as @temporary or 
something like that, and those templates will be reevaluated each time. 
And in the case of something like hasFoo, I'd argue it's just a thin 
wrapper over a __traits call, so it probably should be reevaluated each 
time.

This does not make it non-deterministic, just determined differently. In 
fact, I'd say it's *more* deterministic, as evaluating templates does 
not depend on weird interactions like this. And it should be opt-in to 
avoid breaking code.

But it's also possible that Stefan's solution would work as well, if we 
can manipulate types like variables in CTFE mode.

-Steve


More information about the Digitalmars-d mailing list