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