Jump to page: 1 2 3
Thread overview
static assert(0) in template is a disaster
Jun 16, 2020
Nils Lankila
Jun 16, 2020
rikki cattermole
Jun 16, 2020
Stefan Koch
Jun 16, 2020
Nils Lankila
Jun 16, 2020
Stefan Koch
Jun 16, 2020
Nils Lankila
Jun 16, 2020
Paul Backus
Jun 16, 2020
Nils Lankila
Jun 16, 2020
Dennis
Jun 16, 2020
Paul Backus
Jun 17, 2020
Stefan Koch
Jun 17, 2020
Avrina
Jun 17, 2020
Stefan Koch
Jun 17, 2020
Avrina
Jun 19, 2020
Stefan Koch
Jun 19, 2020
Avrina
Jun 17, 2020
Timon Gehr
Jun 17, 2020
Stefan Koch
Jun 17, 2020
Paul Backus
Jun 17, 2020
Dennis
Jun 17, 2020
Tim
June 16, 2020
Today I've decided to test the new -vtemplates feature.
I don't know if what i've found is already known but it looks like a dormant disaster in phobos.

So if you compile dparse with -vtemplate you'll get for example this strange thing:

>       694      694   AliasThisTypeOf(T) if (isAggregateType!T)

That's for the less very suspicious: 694 instantiations, 694 unique instances !
So I've put a pragma msg in the template to check that every template parameter passed is unique. It's definitively not the case.

`AliasThisTypeOf` is really a simple template that wraps a compiler `__traits`:

>  private template AliasThisTypeOf(T)
>  if (isAggregateType!T)
>  {
>      alias members = __traits(getAliasThis, T);
> 
>      static if (members.length == 1)
>      {
>          alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0]));
>      }
>      else
>          static assert(0, T.stringof~" does not have alias this type");
>  }

The problem can only comes from the assertion. So I've changed the implementation to

>  private template AliasThisTypeOf(T)
>  if (isAggregateType!T)
>  {
>      alias members = __traits(getAliasThis, T);
>
>      static if (members.length == 1)
>      {
>          alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0]));
>      }
>      else
>          alias AliasThisTypeOf = AliasSeq!();
>  }

And recompiled dparse. The results look more coherant now:

>       694      167   AliasThisTypeOf(T) if (isAggregateType!T)

conclusion: avoid static `assert(0)` in templates bodies. They prevent instance uniqueness. `std.traits` contains plenty of them and they should be removed in favor of something similar to what's done here.
June 17, 2020
Bug report please, this may be an issue that can be fixed.
June 16, 2020
On Tuesday, 16 June 2020 at 14:05:28 UTC, Nils Lankila wrote:
> Today I've decided to test the new -vtemplates feature.
> I don't know if what i've found is already known but it looks like a dormant disaster in phobos.
>
> [...]

Are you sure it's not the T.stringof ?
June 16, 2020
On Tuesday, 16 June 2020 at 14:19:06 UTC, Stefan Koch wrote:
> On Tuesday, 16 June 2020 at 14:05:28 UTC, Nils Lankila wrote:
>> Today I've decided to test the new -vtemplates feature.
>> I don't know if what i've found is already known but it looks like a dormant disaster in phobos.
>>
>> [...]
>
> Are you sure it's not the T.stringof ?

yes. I've removed it after changing the else statement.
June 16, 2020
On Tuesday, 16 June 2020 at 14:22:25 UTC, Nils Lankila wrote:
> On Tuesday, 16 June 2020 at 14:19:06 UTC, Stefan Koch wrote:
>> On Tuesday, 16 June 2020 at 14:05:28 UTC, Nils Lankila wrote:
>>> Today I've decided to test the new -vtemplates feature.
>>> I don't know if what i've found is already known but it looks like a dormant disaster in phobos.
>>>
>>> [...]
>>
>> Are you sure it's not the T.stringof ?
>
> yes. I've removed it after changing the else statement.

Thank you very much for finding this.

I'll be having a look at this shortly.
June 16, 2020
On Tuesday, 16 June 2020 at 14:26:18 UTC, Stefan Koch wrote:
> On Tuesday, 16 June 2020 at 14:22:25 UTC, Nils Lankila wrote:
>> On Tuesday, 16 June 2020 at 14:19:06 UTC, Stefan Koch wrote:
>>> On Tuesday, 16 June 2020 at 14:05:28 UTC, Nils Lankila wrote:
>>>> Today I've decided to test the new -vtemplates feature.
>>>> I don't know if what i've found is already known but it looks like a dormant disaster in phobos.
>>>>
>>>> [...]
>>>
>>> Are you sure it's not the T.stringof ?
>>
>> yes. I've removed it after changing the else statement.
>
> Thank you very much for finding this.
>
> I'll be having a look at this shortly.

The problem is quite clear.

If a template fails once to instantiate with a given set of template parameters then it will always fail with the same set of parameters. But if failed instantiation are not stored in

> TemplateInstance[TemplateInstanceBox] instances;

That's sure that this is tried again and again...

Maybe something like an `ErroneousTemplateInstance` class could be added as it's probably not reasonable to have a TemplateInstance instance for something that is not usable.
Then this failed instance could be stored in an additional map, e.g

> ErroneousTemplateInstance[TemplateInstanceBox] failedInstances;
June 16, 2020
On Tuesday, 16 June 2020 at 16:57:50 UTC, Nils Lankila wrote:
> On Tuesday, 16 June 2020 at 14:26:18 UTC, Stefan Koch wrote:
>> On Tuesday, 16 June 2020 at 14:22:25 UTC, Nils Lankila wrote:
>>> On Tuesday, 16 June 2020 at 14:19:06 UTC, Stefan Koch wrote:
>>>> On Tuesday, 16 June 2020 at 14:05:28 UTC, Nils Lankila wrote:
>>>>> Today I've decided to test the new -vtemplates feature.
>>>>> I don't know if what i've found is already known but it looks like a dormant disaster in phobos.
>>>>>
>>>>> [...]
>>>>
>>>> Are you sure it's not the T.stringof ?
>>>
>>> yes. I've removed it after changing the else statement.
>>
>> Thank you very much for finding this.
>>
>> I'll be having a look at this shortly.
>
> The problem is quite clear.
>
> If a template fails once to instantiate with a given set of template parameters then it will always fail with the same set of parameters.

Unfortunately this is not true:

template example(T)
{
    static assert(__traits(hasMember, T, "x"));
    alias example = T.x;
}

struct S
{
    static if (!__traits(compiles, example!S)) {
        int x;
    }
}

static assert(is(typeof(example!S) == int));

June 16, 2020
On Tuesday, 16 June 2020 at 17:06:33 UTC, Paul Backus wrote:
> On Tuesday, 16 June 2020 at 16:57:50 UTC, Nils Lankila wrote:
>> On Tuesday, 16 June 2020 at 14:26:18 UTC, Stefan Koch wrote:
>>> On Tuesday, 16 June 2020 at 14:22:25 UTC, Nils Lankila wrote:
>>>> [...]
>>>
>>> Thank you very much for finding this.
>>>
>>> I'll be having a look at this shortly.
>>
>> The problem is quite clear.
>>
>> If a template fails once to instantiate with a given set of template parameters then it will always fail with the same set of parameters.
>
> Unfortunately this is not true:
>
> template example(T)
> {
>     static assert(__traits(hasMember, T, "x"));
>     alias example = T.x;
> }
>
> struct S
> {
>     static if (!__traits(compiles, example!S)) {
>         int x;
>     }
> }
>
> static assert(is(typeof(example!S) == int));

that's unfortunate, looks like the problem cant be solved then.
June 16, 2020
On Tuesday, 16 June 2020 at 18:14:26 UTC, Nils Lankila wrote:
>> template example(T)
>> {
>>     static assert(__traits(hasMember, T, "x"));
>>     alias example = T.x;
>> }
>>
>> struct S
>> {
>>     static if (!__traits(compiles, example!S)) {
>>         int x;
>>     }
>> }
>>
>> static assert(is(typeof(example!S) == int));
>
> that's unfortunate, looks like the problem cant be solved then.

In my opinion, the fact that that compiles is a blatant bug. However, the D specification is not thorough enough to conclusively say. Even if we define it better and patch the compiler, unfortunately the paradoxical "if this doesn't compile yet, make it compile" pattern has been adopted in the wild so it would be a breaking change. To see why it's problematic, ask yourself why this compiles:

```
static assert(x == 3);
static if (!is(typeof(x))) immutable x = 3;
static if (!is(typeof(x))) immutable x = 5;
```

I've written about this in more detail before:
https://forum.dlang.org/post/tlpogchogwsopswgbpdu@forum.dlang.org



June 16, 2020
On Tuesday, 16 June 2020 at 22:16:34 UTC, Dennis wrote:
> On Tuesday, 16 June 2020 at 18:14:26 UTC, Nils Lankila wrote:
>>> template example(T)
>>> {
>>>     static assert(__traits(hasMember, T, "x"));
>>>     alias example = T.x;
>>> }
>>>
>>> struct S
>>> {
>>>     static if (!__traits(compiles, example!S)) {
>>>         int x;
>>>     }
>>> }
>>>
>>> static assert(is(typeof(example!S) == int));
>>
>> that's unfortunate, looks like the problem cant be solved then.
>
> In my opinion, the fact that that compiles is a blatant bug. However, the D specification is not thorough enough to conclusively say. Even if we define it better and patch the compiler, unfortunately the paradoxical "if this doesn't compile yet, make it compile" pattern has been adopted in the wild so it would be a breaking change. To see why it's problematic, ask yourself why this compiles:
>
> ```
> static assert(x == 3);
> static if (!is(typeof(x))) immutable x = 3;
> static if (!is(typeof(x))) immutable x = 5;
> ```
>
> I've written about this in more detail before:
> https://forum.dlang.org/post/tlpogchogwsopswgbpdu@forum.dlang.org

I agree that this is a bug, but it is a bug in the design of the language itself, not the implementation.

You write in your linked post that

> The 'before' and 'after' are implementation details showing up as a result of underspecification.
>
> Module level declarations are supposed to be order invariant.

...but in fact, the existence of 'before' and 'after' states is an unavoidable consequence of how `static if` works. The condition of a `static if` statement *must* be evaluated before the body is processed by the compiler. Without some mechanism for controlling the order in which declarations undergo semantic analysis, it would be impossible to implement `static if` in the first place.

In more principled languages (e.g., Lisps), this ordering is explicit, and chosen by the programmer: a macro takes the 'before' state as its input and produces the 'after' state as its output, and the programmer is free to compose as many of them as they like in any order. In D, the ordering is implicit, and chosen by the compiler via on-demand semantic analysis, but apart from that it is fundamentally the same.

The ugly truth here is that Walter has designed himself into a corner: module-level declarations are not order invariant in D, and never will be.
« First   ‹ Prev
1 2 3