Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow many positional arguments #17

Closed
Jackojc opened this issue May 12, 2019 · 4 comments · Fixed by #57
Closed

Allow many positional arguments #17

Jackojc opened this issue May 12, 2019 · 4 comments · Fixed by #57
Labels
enhancement New feature or request

Comments

@Jackojc
Copy link
Contributor

Jackojc commented May 12, 2019

It would be nice to be able to have a feature whereby you could gather many positional arguments at the end of a command for something like a compiler.

For example, imagine a use case like this:

compiler file1 file2 file3

Currently I don't believe it is possible to do this.

I imagine using it would look something like:

std::vector<std::string> = program.get_trailing();

which would just return all positional arguments at the end regardless of how many.

@p-ranav p-ranav added the enhancement New feature or request label May 12, 2019
@zhihaoy
Copy link
Contributor

zhihaoy commented Nov 13, 2019

Often cmdline parser updates or returns updated (argc, argv) pair so that other 3rd-party parsers can continue to work on the rest of the arguments.

argparse seems to be working on its own storage, in that case a pair of updated (begin, end) iterators would be similar. For example,

auto [first, last] = program.parse_args(argc, argv);
auto tailing = std::vector(first, last);  // you got the unused arguments

@Jackojc
Copy link
Contributor Author

Jackojc commented Nov 13, 2019

I like that idea, very clean.

@zhihaoy
Copy link
Contributor

zhihaoy commented Nov 14, 2019

Hmm, this is more complicated than I thought.

Must extra arguments be consecutive?

Given the trailing model, let's say

program.add_argument("-I");
program.add_argument("output");

Does this work?

./test pos1 pos2 -I opt1 pos3

If both pos2 and pos1 are deemed unused, then unused arguments must be regathered, so iterator doesn't work (unless we invent our own iterator to do parsing, which would be fancy).

Extra positional arguments are illegal given existing semantics

If the above is deemed illegal, whether anything with unused arguments are legal is still debatable.

./test pos1 -I opt1 pos2 pos3

Given the existing parse_args, the above throws exception. In order to not to introduce a runtime breaking change, we may have to make the behavior configurable. For example, by introducing a continuation:

parse_args(argc, argv, argparse::throw_if_exceeds_maximum_positional_arguments);
// ^^ this is the default, no need to pass the 3rd argument
auto some_return_value = parse_args(argc, argv, argparse::return_trailing_positional_arguments);

Lifetime

parse_args(argc, argv) cannot return iterators that point to std::vector because that's a local variable. At best it can return two pointors into argv, but that's less convenient. parse_args({"test", "-L"}) cannot return iterators at all because that's a temporary. Creating an lvalue overload in additional an rvalue overload can workaround this issue but nobody will actually use the lvalue overload.

Thoughts so far

  1. we need configurable semantics that users can choose
  2. if non-consecutive positional arguments are allowed, we will need storage in, for example, ArgumentParser
  3. if we have storage, lifetime isn't an issue
  4. but if we have storage for these arguments, will users want actions on them? Help messages? That lean towards capturing the extra positional arguments' semantics in Argument...

zhihaoy added a commit to zhihaoy/argparse that referenced this issue Nov 20, 2019
This kind of argument works as if having the "remaining" nargs,
inspired by Python's `argparse.REMAINDER`.

This change also reduces the size of `Argument` by 8 bytes.

See also: https://docs.python.org/2/library/argparse.html#nargs

fixes: p-ranav#17
@zhihaoy
Copy link
Contributor

zhihaoy commented Nov 21, 2019

I studied Python's argparse, and was convinced that there are two demands.

The first one is to have a kind of Argument that expects "remaining" number of arguments. The argument itself maybe positional or optional. It consume everything, regardless positional or optional, until the end.

The second one is to parse known arguments, and leave the rest to other libraries. The rest of the arguments are not associated with argparse::Argument and actions don't work on them.

The demand raised in this issue is the former, and I drafted #57 for it. The second demand is worth to investigate separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants