-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
What is the right approach for a typed API #3792
Comments
This is the derive support for clap-rs#3774 (see also clap-rs#3775, clap-rs#3777) This combined with `value_parser` replaces `parser`. The main frustration with this is that `ArgAction::Count` (the replacement for `parse(from_occurrences)` must be a `u64`. We could come up with a magic attribute that is meant to be the value parser's parsed type. We could then use `TryFrom` to convert the parsed type to the user's type to allow more. That is an exercise for the future. Alternatively, we have clap-rs#3792. Prep for this included - clap-rs#3782 - clap-rs#3783 - clap-rs#3786 - clap-rs#3789 - clap-rs#3793
I don't really see a need for it to work with other types. Am I missing something?
Yes, we shouldn't be storing raw values once we store typed ones.
The typed approach is more suited for derive parser and I wouldn't mind if the users have to do it.
I am not sure why we needed this. Ideally we should prefer to avoid this, but I would consider this low priority. |
Thanks for the feedback! I appreciate a sounding board on this especially with how invasive of a change this is and how much work it is for users to migrate if we change this too soon due to the API's pervasiveness. To confirm / summarize, it sounds like, at a high level, you are comfortable with what is currently in
Most users today are using it with a mixture of types. Technically, As for the choice in type, I was torn on what to make the upper bound, so I just left it as a basic
This might make
So that requires some more caveats. We actually are storing |
Ah, yeah.
Yup, that is what I was thinking too before. As I said, the |
Someone should not reasonably expect a coun flag to go up to billions, millions, or even thousands. 255 should be sufficient for anyone, right? The original type was selected to be consistent with `ArgMatches::occurrences_of` but that is also used for tracking how many values appear which can be large with `xargs`. I'm still conflicted on what the "right type" is an wish we could support any numeric type. When I did a search on github though, every case was for debug/quiet flags and only supported 2-3 occurrences, making a `u8` overkill. This came out of a discussion on clap-rs#3792
As an update, I did just find #408 which is where clap went from using u8 everywhere to u64. That was more focused on number of values though it also tests for a large number of flag occurrences. I'm not seeing any associated use cases or reason we need to support counting that many flags, so I don't think this changes anything. |
The default, I believe, should be As to why people use different types, experience with MCU programming taught me to be frugal with types, so I default to using the smallest type which will fit my value. On the other hand, for Clap's use case you are right that this doesn't particularly matter.
Looking through the official platform support document there are 16 bit and even 8 bit targets in Tier 3 (may or may not work, no guarantees). Nothing lower than 32 bit in T1 or T2. I think |
Container lengths are limited by the size of memory, so it makes sense there. But I'd say that:
|
I've been working on swtiching to the new 3.2 non-deprecated apis, and one pain point I've run into is |
I had considered finding some type tricks to pull to allow specifying the borrowed type. My concern with it was on the usability
Now, we could also consider In an ideal world, we'd also implicitly copy any |
Some other things that are less ergonomic than one might hope:
|
Thank you for your feedback on this. When considering the trade offs, I went forward with the less ergonomic API due to what it allows but recognizing the cost. The assumption going into it was that people tend to prefer the Derive API for ergonomics and the Builder API for control, so reducing the ergonomics a little for improved control seemed aligned. Feedback like this helps in evaluating whether this is the right decision.
The iterators should be implementing |
Since 3.2 came out, there has been some grumbling about the ergonomics but I think it went well enough that we no longer need to proactively track alternatives. Instead we can wait for more concrete user reports. |
This is a follow up to #2683
State of Clap 3.0
Clap's builder API only natively supports two types,
OsString
andString
, controlled viaArg::allow_invalid_utf8
and then accessed viaArgMarches::value_of{,_os}
.The user can provide extra validation via
Arg::forbid_empty_value
Arg::possible_values
Arg::validator
Arg::validator_regex
ArgMatches::value_of_t
then adapts to the user type viaFromStr
.clap_derive
allows users to set a custom adapter to their type (instead of the fixed one ofvalue_of_t
. This then automatically gets put in as anArg::validator
, causing it to be run twice (#3589).This requires users to know how to use
Path
s correctly, see #3496Basic Builder
Output:
(note: no coloring)
Basic Derive:
Output:
State of 3.2
With #3732 and many follow up, we've made the API typed. This removes all of those extra validators and makes the builder API closer to the derive API.
Basic Builder
Output:
Problems with this approach:
parse(from_occurrences)
only works withu64
and only through docs / asserts can we tell usersArg::value_parser
withArgMatches::get_one::<T>
std::any::Any + Clone + Send + Sync + 'static
, beforeClone
wasn't required, allowing it to be used with more typesstd::fmt::Debug
...(Vec<Box<T>>, Vec<OsString>)
, causing an extra allocation per value while still having to have theOsString
for validationany_vec
might help in the future to takeVec<Box<T>>
toVec<T>
Alternatives
Double-down on storing
OsString
OsString
get_one::<T>(id, typed_value_parser)
would replacevalue_of_t_or_exit
(try_
would replace the non-exit
version)try_get_one
/try_get_many
Compared to the 3.0 solution
Arg::possible_values
Compared to the 3.2 solution
ArgAction::Count
would support any type, unlike the 3.2 solutionvalue_parser
would likely not be as featurefulvalue_parser
wouldn't have access to look upignore_case
but would need its own independentignore_case
Arg::possible_values
Command
for color support, knowing what help to suggest and access toArg
for showing the flag name or checking if ignore case is set (used also by the default/required rules)Parser
would be slightly better because we would callerr.format(&mut cmd)
implicitly. If the user usesCommandFactory
/FromArgMatches
directly, they are on their ownThe text was updated successfully, but these errors were encountered: