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 :) !

Reply via email to