static assert not printing out along the error diagnostic

someone someone at somewhere.com
Thu Jul 15 01:16:10 UTC 2021


On Wednesday, 14 July 2021 at 23:44:18 UTC, jfondren wrote:
> On Wednesday, 14 July 2021 at 22:59:38 UTC, someone wrote:
>> [...]
>
> so, these lines:
>
> ```d
>     stringUGC32 lugcSequence3 = stringUGC32(cast(char) 'x');
>     stringUGC32 lugcSequence4 = stringUGC32(1);
> ```
>
> which call stringUGC32, an alias:
>
> ```d
> alias stringUGC32 = gudtUGC!(stringUTF32);
> alias stringUTF32 = dstring; /// same as immutable(dchar)[];
> ```
>
> which explicitly instantiates gudtUGC with the type dstring,
>
> ```d
> enum isTypeSupported(type) = is(type == stringUTF08) || is(type 
> == stringUTF16)
>     || is(type == stringUTF32);
> ...
> public struct gudtUGC(typeStringUTF) {
>     static assert(isTypeSupported!(typeStringUTF),
>             r"ooops … gudtUGC structure requires 
> [string|wstring|dstring] ≠ ["d
>             ~ typeStringUTF.stringof ~ r"]"d);
> ```
>
> which passes the assert.
>
> You're explicitly instantiating the struct with dstring, *not 
> getting an assertion error because dstring passes the test*, 
> and are then passing the constructor a different type, which 
> gets you a type error at that time.

I can't believe I completely forgot about my alias; I am a stupid 
to the say the least, I raised this issue without thinking much :(

> However, even if you avoid that alias and try either implicit 
> or explicit instantiation of the template with bad types, the 
> template instantiation fails first in random other places, like 
> a default param of " " not making sense as a char:
>
> ```d
> staticif1.d(369): Error: cannot implicitly convert expression 
> `" "` of type `string` to `const(char)`
> staticif1.d(387): Error: cannot implicitly convert expression 
> `" "` of type `string` to `const(char)`
> staticif1.d(545): Error: template instance 
> `fw.types.UniCode.gudtUGC!char` error instantiating
> ```
>
> So, yeah, even with no static ifs in the file, you're still not 
> getting these static asserts to fail before other parts of the 
> template. Conclusion: you shouldn't rely on static asserts 
> providing a good UI in the case of an error. They still *work*, 
> the struct still wouldn't instantiate with a `char` or the like 
> if all the other char-incompatibilities were removed, but for 
> UI purposes they're not great because you can't rely on them 
> firing according to normal control flow.

ACK for the static asserts.

> You're using aliases though, and not instantiating the struct 
> directly. If you make those function templates you can use 
> template constraints with them, which does result in a nice UI:

A few days ago when I started coding this UDT (and started 
thinking of *actually using it*) the first thing that came to 
mind was that to get a simple, say, strWhatever.left(1) I would 
end up writing gudtUGC!(dstring)(strWhatever).left(1).encode() or 
gudtUGC!(dstring)(strWhatever).leftAsUTF(1) or something akin to 
these ones, so I played a bit with the aliases and ended up with 
gudtUGC[08|16|32] which seemed a bit more friendly and 
crystal-clear on their types. The thing with aliases is that they 
are really useful *until* you forgot you're using aliases and end 
up biting yourself on a situation like this one. Again, sorry for 
being too silly on my part.

> ```d
> gudtUGC!stringUTF08 thing8(T)(T arg) if (isTypeSupported!T) { 
> return gudtUGC!T(arg); }
> gudtUGC!stringUTF16 thing16(T)(T arg) if (isTypeSupported!T) { 
> return gudtUGC!T(arg); }
> gudtUGC!stringUTF32 thing32(T)(T arg) if (isTypeSupported!T) { 
> return gudtUGC!T(arg); }
>
> ...
>
>     stringUGC32 lugcSequence3 = thing32(cast(char) 'x');
>     stringUGC32 lugcSequence4 = thing32(1);
> ```
>
> (introducing new 'thing' functions as stringUGC32 used is 
> elsewhere as a type and not just a function. So you still need 
> the aliases.)
>
> Which fails in this manner:
>
> ```d
> staticif1.d(548): Error: template `fw.types.UniCode.thing32` 
> cannot deduce function from argument types `!()(char)`, 
> candidates are:
> staticif1.d(46):        `thing32(T)(T arg)`
>   with `T = char`
>   must satisfy the following constraint:
> `       isTypeSupported!T`
> ```
>
> and would fail more verbosely if the three functions had the 
> same name, instead of numbered names to follow the stringUGC32 
> pattern.
>
> `isTypeSupported` isn't great here, but you can pick a more 
> precise name. Or in the case of already numbered functions like 
> this, you could use more precise tests... or just drop the 
> tests entirely and have non-templated functions:
>
> ```d
> gudtUGC!stringUTF08 thing8(stringUTF08 arg) { return 
> typeof(return)(arg); }
> gudtUGC!stringUTF16 thing16(stringUTF16 arg) { return 
> typeof(return)(arg); }
> gudtUGC!stringUTF32 thing32(stringUTF32 arg) { return 
> typeof(return)(arg); }
> ```
>
> which results in normal type errors:
>
> ```
> staticif2.d(548): Error: function 
> `fw.types.UniCode.thing32(dstring arg)` is not callable using 
> argument types `(char)`
> staticif2.d(548):        cannot pass argument `'x'` of type 
> `char` to parameter `dstring arg`
> ```

I will explore this approach.

Thank you very much for your time and your detailed step-by-step 
reply. I guess you were LoL when you first saw this one :) !


More information about the Digitalmars-d-learn mailing list