On Thursday, 17 March 2022 at 19:07:28 UTC, H. S. Teoh wrote:
Using independent, orthogonal UDAs may make option specification using your module easier to read. For example, from your docs:struct T { @(NamedArgument.PreValidation!((string s) { return s.length > 1 && s[0] == '!'; }).Parse !((string s) { return s[1]; }) .Validation !((char v) { return v >= '0' && v <= '9'; }) .Action !((ref int a, char v) { a = v - '0'; }) ) int a; } could be rewritten with multiple UDAs as: struct T { @NamedArgument@PreValidation!((string s) { return s.length > 1 && s[0] == '!'; })@Parse !((string s) { return s[1]; }) @Validation !((char v) { return v >= '0' && v <= '9'; }) @Action!((ref int a, char v) { a = v - '0'; }) int a; }It might also simplify your implementation by having more smaller, independent pieces for each UDA instead of a single complex UDA that handles everything.
I use UDAs extensively in my project and I've historically been doing the multiple-UDA approach you describe. Upon seeing argparse a few months back I started rewriting it to use a single UDA, and I found it allowed for a simpler implementation (and not the other way around).
The immediate gains boiled down to that I could now pass what is essentially a context struct around at CTFE instead of keeping track of multiple variables. Default values are also much easier to manage with much fewer `hasUDA`s sprinkled everywhere.
One drawback is documentation; adrdox does *not* like these kinds of UDAs.
