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

Simplify parsing numeric arguments with predefined actions #63

Closed
lichray opened this issue Nov 23, 2019 · 1 comment · Fixed by #65
Closed

Simplify parsing numeric arguments with predefined actions #63

lichray opened this issue Nov 23, 2019 · 1 comment · Fixed by #65

Comments

@lichray
Copy link
Contributor

lichray commented Nov 23, 2019

Currently, we have no predefined actions at all (other than identity), and this is an obvious use case to improve. Asking users to write lambdas to parse raises the bar for use, and difficult to upgrade to a <charconv> future. For the most common inputs, users should be able to express what do they expect rather than how do they handle.

Python's argparse provides type=int and type=float, which do not take hexadecimal inputs and are lack of support for types of different ranges (int, long, etc.) We need to able to express both for C++ applications.

I propose to add a .scan method to the fluent interface, inspired by scanf. I took the name from scnlib. Usage looks like the following:

program.add_argument("-x")
       .scan<'d', int>();
program.add_argument("scale")
       .scan<'g', double>();

The non-type template argument specifies how the input "looks like" (where I call it shape), and the type template argument specifies what the return value of the predefined action is. The acceptable types are:

  • floating point: float, double, long double
  • integral (+ make_unsigned): signed char, short, int, long, long long

and the acceptable shapes are:

  • floating point:
    • 'a': hexadecimal floating-point
    • 'f': fixed form only
    • 'e': scientific form only
    • 'g': general form (either fixed or scientific)
  • integral:
    • 'd': decimal
    • 'u': decimal, requires an unsigned type
    • 'o': octal, requires an unsigned type
    • 'x': hexadecimal, requires an unsigned type
    • 'i': anything that from_chars's grammar accepts in base == 0

The exact grammar should follow from_chars's requirement. But our first implementation may still use strtol and strtod. When encounters errors, throw exceptions similar to what stoi and stod do.

FAQ

  1. Can I omit the type? No.
  2. Can I omit the shape? Not for these. from_chars and strto? default to parse anything, but Python's type=int and type=float only parse decimal. I'm not sure whether we can agree on a default. But when extending this for other types in the future, we may.
  3. How to extend this to other common types? Let's keep an eye on how the Text parsing proposal evolves.
  4. Why using non-type template parameters? So that we can select predefined actions at compile-time and go straight assigning one to mAction in each call to scan.
  5. Can auto non-type template parameter help? Sadly no. .scan<int('d')>() is okay but .scan<(unsigned long)'x'> is terrible.
  6. Can we support uppercase shapes like 'X'? What do you expect them to do? I guess letting them behave as same as the lowercase counterparts is the only reasonable answer. If we agree on that, I'm okay with it.
@p-ranav
Copy link
Owner

p-ranav commented Nov 25, 2019

Your proposal sounds good to me.

lichray added a commit to lichray/argparse that referenced this issue Nov 26, 2019
lichray added a commit to lichray/argparse that referenced this issue Nov 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants