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.