www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - How std.getopt would look with type functions

reply Stefan Koch <uplink.coder googlemail.com> writes:
Just now I thought about one of the things that always irked me 
about variadic template parameter lists. The lack of type 
checking.
And the wired errors which are getting caught far too late in the 
template instance stack.

Let's take std.getopt as an example.
The first example givin in it's docs is this

  auto helpInformation = getopt(
     args,
     "length",  &length,    // numeric
     "file",    &data,      // string
     "verbose", &verbose,   // flag
     "color", "Information about this color", &color);    // enum

The pattern is clear it's a tuple representing {name, 
pointer_to_var} excpect when the second parameter is not a 
pointer but a string in which case it's {name, helptext pointer, 
to var} or maybe just forgot to pass another pointer to a var in 
there ? And "Information about this color" is just a very  long 
option name?

type functions can easily fix that.
Since they also introduce the ability to store references to 
symbols in structs.

struct arg { string name; alias var; string help = null }
getOps(args, arg("length", length),
              arg("file", data),
              arg("verbose", verbose),
              arg("color", color, "Information about this color")
);

I argue that this is firstly more type safe.
And secondly looks much nicer.
getopt could be defined as getopt(string args, arg[] args...)
and one could leave the fiddling to detect how to interpret which 
part of the argument list
out of the getopt implementation.
May 23
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 24 May 2020 at 00:15:07 UTC, Stefan Koch wrote:
 struct arg { string name; alias var; string help = null }
 getOps(args, arg("length", length),
              arg("file", data),
              arg("verbose", verbose),
              arg("color", color, "Information about this color")
 );
Ah wrong args[]... have to go into the template parameter list. At least for now. it would look more like getOps!(arg("length", length), arg("file", data), arg("verbose", verbose), arg("color", color, "Information about this color"))(args); The point still stands though.
May 23
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 24 May 2020 at 00:23:31 UTC, Stefan Koch wrote:

 Ah wrong args[]... have to go into the template parameter list.
 At least for now. it would look more like
 getOps!(arg("length", length),
        arg("file", data),
        arg("verbose", verbose),
        arg("color", color, "Information about this 
 color"))(args);
We can do this today (just the template args would be implicit).
May 23
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 24 May 2020 at 03:43:58 UTC, Adam D. Ruppe wrote:
 On Sunday, 24 May 2020 at 00:23:31 UTC, Stefan Koch wrote:

 Ah wrong args[]... have to go into the template parameter list.
 At least for now. it would look more like
 getOps!(arg("length", length),
        arg("file", data),
        arg("verbose", verbose),
        arg("color", color, "Information about this 
 color"))(args);
We can do this today (just the template args would be implicit).
Yes but that's no reason to not show how it would look?
May 24
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 24 May 2020 at 07:06:31 UTC, Stefan Koch wrote:
 Yes but that's no reason to not show how it would look?
getopt( arg("whatever", "help", whatever), arg("other", other) ); It is identical to what you wrote except with implicit template args. getopt there is still a variadic template, arg is a factory function (with two overloads, with and without the help string) that returns a templated struct. The getopt is free to static assert fail if an argument isn't of the typeof(arg). The final arg is either an explicit pointer or a ref argument that takes the address internally for the return value. No fancy feature needed here.
May 24
prev sibling parent Basile B. <b2.temp gmx.com> writes:
On Sunday, 24 May 2020 at 00:15:07 UTC, Stefan Koch wrote:
 Just now I thought about one of the things that always irked me 
 about variadic template parameter lists. The lack of type 
 checking.
 And the wired errors which are getting caught far too late in 
 the template instance stack.

 Let's take std.getopt as an example.
 The first example givin in it's docs is this

  auto helpInformation = getopt(
     args,
     "length",  &length,    // numeric
     "file",    &data,      // string
     "verbose", &verbose,   // flag
     "color", "Information about this color", &color);    // enum

 The pattern is clear it's a tuple representing {name, 
 pointer_to_var} excpect when the second parameter is not a 
 pointer but a string in which case it's {name, helptext 
 pointer, to var} or maybe just forgot to pass another pointer 
 to a var in there ?
No but there's an optional parameter that is that the flags can be overridden before each new serie of parameters, but well this is essentially a pattern... just add this to the tuple and adjust the flag so that "no flag" means "keep processing as previously".
 And "Information about this color" is just a very  long option 
 name?

 type functions can easily fix that.
 Since they also introduce the ability to store references to 
 symbols in structs.

 struct arg { string name; alias var; string help = null }
 getOps(args, arg("length", length),
              arg("file", data),
              arg("verbose", verbose),
              arg("color", color, "Information about this color")
 );

 I argue that this is firstly more type safe.
 And secondly looks much nicer.
 getopt could be defined as getopt(string args, arg[] args...)
 and one could leave the fiddling to detect how to interpret 
 which part of the argument list
 out of the getopt implementation.
I and others use UDA in a very similar fashion [1], which makes the driver of an application ridiculously nice looking [2]. [1] https://gitlab.com/basile.b/dexed/-/blob/4f63afb30a43b9ac52ba724f0518986e1490d1ff /dastworx/src/main.d#L55 [2] https://gitlab.com/basile.b/dexed/-/blob/4f63afb30a43b9ac52ba724f0518986e1490d1ff/dastworx/src/main.d#L22 having the possibility to store a reference to a function or to a value without using pointers is a key feature for making getopt safe BTW. As a bonus, once you have direct access to the arguments targets the whole getopt processing can be adapted to the arguments, i.e static foreach (unrolling).
May 23