On Tuesday, 1 August 2017 at 17:46:57 UTC, H. S. Teoh wrote:
I think UDA-driven configuration parsing is ultimately the
right direction to go. And by that I mean more than just
command-line parsing, but the parsing of configuration
parameters in general, including command-line options,
configuration files, etc.. Usually a lot of boilerplate is
involved in constructing a parser, enumerating options, then
mapping that to configuration variables, adding helpful
descriptions, etc.. All of which are a maintenance burden on
the programmer, because any of these components can become
out-of-sync with each other: the parsing of parameters, the
mapping of these parameters to internal variables, and the help
args.d uses the same parser for command line options and for the
The parser gets adapted between the two with some compile time
With UDAs, it's possible to unify all three in one declaration,
thereby ensuring things will never go out-of-sync, and also
greatly reduces the amount of boilerplate the programmer has to
I didn't look too closely at args.d yet, but in my
implementation, I have UDAs for specifying alternate names for
common configuration parameters (e.g., "outfile=..." instead of
"outputFilename=..."). This allows more user-friendly option
names, and also decouples it from internal variable naming
I found that good variable names make good command line option
And you remove one indirection, which I always like.
Plus, you can always use short options, which are checked for
uniqueness at compile time by args.d.
There's also UDAs for optionally flattening a nested struct, so
that internally I can have separate structs for configuring
each module, but the main program combines all of them into a
single flattened struct, so that to the user all the options
are top-level (can specify "outfile=..." instead of
"backend.outputFilename=..."). The user shouldn't need to know
how the program is organized internally, after all, yet I can
still properly encapsulate configuration parameters relevant to
only that module, thereby avoiding spaghetti dependencies of
modules on a single global configuration struct.
I thought about that as well, but didn't do it because if found:
--mysql.ipAddress Type: string default: localhost
--redis.ipAddress Type: string default: localhost
looks and works just awesome.
At least better than --mysqlipAddress and --redisipAddress.