Thread overview
[Issue 11737] New: Allow optional string value for getopt switches
Dec 14, 2013
arttu.h@yandex.com
Dec 15, 2013
Andrej Mitrovic
Dec 15, 2013
Orvid King
Dec 15, 2013
Orvid King
Dec 15, 2013
Andrej Mitrovic
December 14, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737

           Summary: Allow optional string value for getopt switches
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Phobos
        AssignedTo: nobody@puremagic.com
        ReportedBy: arttu.h@yandex.com


--- Comment #0 from arttu.h@yandex.com 2013-12-13 20:46:20 PST ---
Say you want a command line switch like --log. This should enable logging to a predefined file default.log. User should also be able to use --log=somefile.log to define where things should be logged.

I tried to achieve this with getopt, but couldn't find a way for it. Adding --log twice to getopt doesn't work as it just throws an exception if the given value doesn't fit whatever was added first.

Perhaps there are some workarounds for this such as using config.passThrough and manually handling --log. However, as this is quite common in command-line parsing, it would be a nice addition to getopt.

One way this could be achieved: allow an option that takes a string value, but can be used without a value, in which case the string is set to a default value.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737


Andrej Mitrovic <andrej.mitrovich@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrei@erdani.com,
                   |                            |andrej.mitrovich@gmail.com


--- Comment #1 from Andrej Mitrovic <andrej.mitrovich@gmail.com> 2013-12-15 10:54:11 PST ---
I'm thinking of the following, this current code will allow --log=value, but not --log:

-----
import std.getopt;
import std.stdio;

void main(string[] args)
{
    getopt(args,
           "log",
           (string option, string value)
           {
                // store value here
                writeln(value);
           });
}
-----

$ rdmd test.d --log=foo
> foo

$ rdmd test.d --log
> object.Exception@C:\dmd-git\dmd2\windows\bin\..\..\src\phobos\std\getop
t.d(486): Missing value for argument --log.

So it's meant to catch bugs. However I think we can extend this, and make getopt check whether the value parameter has a default initializer:

-----
import std.getopt;
import std.stdio;

void main(string[] args)
{
    getopt(args,
           "log",
           (string option, string value = "bar")  // should allow '--log'
           {
               // value is either set (e.g. --log=foo), or set to "bar" (--log)
               writeln(value);
           });
}
-----

That way we don't break code and introduce this new feature. Andrei, thoughts?

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737



--- Comment #2 from Andrei Alexandrescu <andrei@erdani.com> 2013-12-15 11:02:22 PST ---
I think the default argument trick is quite neat. Andrej, would you care to implement it?

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737


Orvid King <blah38621@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |blah38621@gmail.com


--- Comment #3 from Orvid King <blah38621@gmail.com> 2013-12-15 11:19:26 PST ---
(In reply to comment #2)
> I think the default argument trick is quite neat. Andrej, would you care to implement it?

I'm sure he'd love to implement it, but delegate and function pointer types don't currently keep any information on the name or default value of their parameters, meaning that this is currently impossible without declaring a function and passing it as an alias template parameter.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737



--- Comment #4 from Andrei Alexandrescu <andrei@erdani.com> 2013-12-15 11:24:12 PST ---
Upon a bit more thinking, the trick is rather subtle. Perhaps it would be more straightforward to allow two lambdas with the same option, and invoke the appropriate one.

import std.getopt;
import std.stdio;

void main(string[] args)
{
    getopt(args,
           "log",
           (string option)  // should allow '--log'
           {
           },
           "log",
           (string option, string value)  // should allow '--log=value'
           {
           });
);
}

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737



--- Comment #5 from Orvid King <blah38621@gmail.com> 2013-12-15 11:31:44 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > I think the default argument trick is quite neat. Andrej, would you care to implement it?
> 
> I'm sure he'd love to implement it, but delegate and function pointer types don't currently keep any information on the name or default value of their parameters, meaning that this is currently impossible without declaring a function and passing it as an alias template parameter.

I just realized this probably came off a wee bit more confrontational than I meant it to, woops. Either way, I think the default value option for a delegate is a beautiful way to solve the problem, as I think having 2 separate delegates is just a bit too verbose, especially as they are likely to contain the exact same code.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
December 15, 2013
https://d.puremagic.com/issues/show_bug.cgi?id=11737



--- Comment #6 from Andrej Mitrovic <andrej.mitrovich@gmail.com> 2013-12-15 12:30:23 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > I think the default argument trick is quite neat. Andrej, would you care to implement it?
> 
> I'm sure he'd love to implement it, but delegate and function pointer types don't currently keep any information on the name or default value of their parameters, meaning that this is currently impossible without declaring a function and passing it as an alias template parameter.

getopt is a variadic template, so it's possible to extract this information:

-----
import std.traits;

void getopt(T...)(ref string[] args, T opts)
{
    static assert(ParameterDefaultValueTuple!(opts[1])[1] == "bar");
}

void main(string[] args)
{
    getopt(args,
           "log",
           (string option, string value = "bar") { });
}
-----

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------