-
-
Notifications
You must be signed in to change notification settings - Fork 1.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
clap_derive: Vec/Option<Vec> behavior is inconsistent with other types #1772
Comments
I strongly disagree on this. A vector can have 0 elements, and that's the most used case. If you need at least one, you can add |
If we use
|
The
Can you explain what this means? I don't understand the sentence. I think we should have |
I really disagree. Most of the time you're using a Vec, you just want the list of parameters, and you don't really care if an empty parameter was provided. Forcing using an option of vec in the most common case would impact a lot the ergonomics. |
Here is a use case where I find structopt very confusing: paritytech/substrate@6b0eed4 When I read the struct I see that listen_addr is a required argument and port is optional. But the structopt parameters shows me that both arguments are conflicting. Before that commit, the parameters weren't declared as conflicting and I had no way to know that listen_addr was actually optional. The only way I could know that is by reading the table. I personally do think that I invite you to read the lengthy discussion here.
Maybe but it will be consistent with the rest of the API. |
Pff, it took me some time to get back to, sorry for the delays guys.
That issue is related here indeed, but we can't leave it out of this discussion because this is about defaults in derive, not about distinguishing between the two.
@TeXitoi I see your point about But we wouldn't be forcing anything! Users would still be very much able to do struct Opts {
// This Vec is not option so it's required BY DEFAULT
// because it's not bool and not Option
required_vec: Vec<u32>,
// We can override default behavior
// while keeping the raw Vec
#[clap(required = false)]
not_required_vec: Vec<u32>,
// We can use Option<Vec> instead of overriding
// We lose some of the ergonomics but acquire the
// ability to distinguish between <empty list> an <no option at all>
opt_vec: Option<Vec<u32>>
} In other words, this is question of good defaults, and I believe I've found the answer. I think that our willingness of changing defaults should depend of what the most widespread usage is in practice. I decided to check via grep.app and this has been eye opening for me: (IMPORTANT: this research assumes that
attributes with regexes, speak up!)
|
I don't agree with this. Maybe all of them tried Also, we are not technically breaking this because this a separate library
Note:
By default, if one wants to support a
|
Sounds very unlikely, but maybe. @TeXitoi , has anybody ever told you something like "I tried
I agree, absolutely. But we aren't talking just about breaking changes, we're talking about good defaults and whether it's worth to change them. If we find that the current defaults are not optimal, we shall change them, otherwise we shall leave them as is.
Eleven ( I like your
This is exactly what |
This part of reply ended up being literally drenched in sarcasm, an therefore was moved to it's own comment. I'm not blaming anyone and neither I mean to offend anybody. Just stating that the state of affairs is ridiculous. Sure thing. According to 2.x docs. Well, let's test it! Playground extern crate clap;
use clap::{App, Arg};
fn main() {
let m = App::new("app")
.arg(Arg::with_name("arg").multiple(true).takes_value(true))
.arg(Arg::with_name("opt").long("foo").multiple(true).takes_value(true))
.get_matches_from(&["test", "val1", "val2", "--foo", "optv1", "optv2"]);
println!("{:?}", m.values_of("arg").unwrap().collect::<Vec<_>>());
println!("{:?}", m.values_of("opt").unwrap().collect::<Vec<_>>());
} So, we expect it to error, right?
Wait, what? In practice, I've seen a lot of people taking Well, the master is much better! Right? Right. You'd expect it to be documented properly...
Of course. "May appear only once". Crystal clear. What the function looks like?
Sarcasm aside, I very much like how it's done in master:
Well done. Well done indeed. No sarcasm, the API is clear and tidy. Except copy-pasting docs and examples from 2.x probably wasn't the brightest idea. |
I've never seen any question about |
Also, the last like of @pksunkara 's table is impossible unless user explicitly specifies
|
In that case, assume that I meant What do you mean by |
In clap 2: it does so explicitly, this is documented:
In clap 3: not explicitly, I haven't been able to locate the place this is handled in, but I just checked this program: use clap::{App, Arg};
fn main() {
let m = App::new("app")
.arg(Arg::with_name("opt").long("foo").multiple_values(true))
.get_matches();
println!("{:?}", m.values_of("opt").map(|v| v.collect::<Vec<_>>()));
} And yes, it works just like if
|
@kbknapp Since we have you here, please take a look at this issue. |
Actually, if you wrap your head around the terminology a bit, it becomes quite clear:
It's a problem of good documentation more than anything, about the way it conveys this setup to user. I'm amending my previous statement about |
Whew ok that was a read! Ever time I see issues pop up around Then clap 2 came around and there was confusion when people wanted multiple values, but not multiple occurrences, or vice versa. It was also over-loaded with flags which only occurrences are possible. This spawned things like Looking back, I wish I'd made the sane default of I also wanted to use the 3.x breaking changes to fix this confusion once and for all. I have a much better idea of what is most common. I want the defaults to be the most common case, and allow those who need something different be able to do so. Unfortunately before I went on hiatus I didn't finish the docs which I'm sure has lead to even more confusion around the various types of multiples, and their defaults or interactions with each other. I see multiples as one of those things, "It sounds sooo simple at first, why can't it just work!?" Until you dig into the details and realize, "Ooooh. Yeah I can totally see how some would want X while others need Y, and you need to distinguish between them sometimes, but not always." It's kind of like Strings in that manner; such a simple concept yet so hard to do correctly. ...Or CLIs for that matter 😜 Ok, so back to the topic at hand: I find myself agreeing with @CreepySkeleton here. We're talking about sane defaults. I can also totally respect @TeXitoi's sentiment of So I think this comes down to balancing Rust ergonomics and semantics ( I would suggest simply calling it out in the docs directly, that although the default is Also, perhaps I'm out of touch, but if I wanted to allow multiple values with occurrences via derive in clap I'd instinctivily try to do
Correct. That is intended behaviour due to how parsing is structured. I don't think there is anything we can, or would want to do about this.
100% agree. Having said all that, if we settled on |
I just came here from TeXitoi/structopt#396 and wanted to say, I really hope in a v3 breaking change, Clap can address the
+100 this bit. It really sticks out as a trap in what's generally a friendly API, and is exacerbated by the fact that you can easily not notice the bug is there. |
Catching up on this issue. Sorry if I missed something or am just repeating others. Multiple values: From a code author and user perspective, I have found variable number of values ( Delimited values: When I want to support multiple values, I tend to do it with a delimiter ( When I'm writing a CLI, I tend to prefer multiple occurrences with delimited values all flattened, There tends to be some friction in this process, so I tend to only do it when I really need it. When I do skip on one, I skip on delimited values, preferring multiple occurrences. It tends to be more composable. If I need require at least one value, it is across both occurrences and delimited values.
So far, the talk seems to be about Something being left out is alternative mental models, like focusing on the type's semantics, for which So let's break down some type semantics:
(we don't have a native type for "1 or more" ( And with the notes at the top, our considerations are:
My proposal would be to match the type semantics, focusing on occurrences:
Note: one downside to implementing any intuitive behavior is people have to predict both what was intuitive to you and how complete your implementation is. No-intuitive behavior is fully explicit and predictable. A theoretical fully-intuitive system would be, by definition, predictable. When you land in the middle, people feel some uncertainty. How quickly that uncertainty is dispelled is proportionate to the quality of your library(1) in framing (API design, docs explaining) (2) making it quick to answer questions (reference). As an aside, I think |
Tuples and other adapters can be handled/discussed in #1717. What we need to finalize in this issue are the |
To clarify, my intent was not to pull #1717 into this but to look at the problem holistically to see how it can affect decisions made here. |
I think we need to first decide on a table like https://docs.rs/structopt/0.3.22/structopt/#type-magic |
I noticed this while investigating clap-rs#2692. Since we are making multiple-occurrences a thing for positional arguments, this allows us to remove a special case. Another way to look at this is that we should make the default whatever we do for dervies (clap-rs#1772). I'm going to propose we make the derive always turn `Vec<i32>` into multiple occurences and not multiple values (with users being able to change it through attributes), but that is an in-work proposal and not decided yet.
I noticed this while investigating clap-rs#2692. Since we are making multiple-occurrences a thing for positional arguments, this allows us to remove a special case. Another way to look at this is that we should make the default whatever we do for dervies (clap-rs#1772). I'm going to propose we make the derive always turn `Vec<i32>` into multiple occurences and not multiple values (with users being able to change it through attributes), but that is an in-work proposal and not decided yet. BREAKING CHANGE: `Arg::from(...)` will now use `multiple_occurrences` for a positional `...`, rather than `multiple_values`.
I noticed this while investigating clap-rs#2692. Since we are making multiple-occurrences a thing for positional arguments, this allows us to remove a special case. Another way to look at this is that we should make the default whatever we do for dervies (clap-rs#1772). I'm going to propose we make the derive always turn `Vec<i32>` into multiple occurences and not multiple values (with users being able to change it through attributes), but that is an in-work proposal and not decided yet. BREAKING CHANGE: `Arg::from(...)` will now use `multiple_occurrences` for a positional `...`, rather than `multiple_values`.
In experimenting on clap-rs#1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for clap-rs#1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke.
In experimenting on clap-rs#1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for clap-rs#1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke.
In experimenting on clap-rs#1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for clap-rs#1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke.
In experimenting on clap-rs#1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for clap-rs#1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke.
In experimenting on clap-rs#1772, I want to write test cases for various combinations of required or not, values vs occurrences, etc. There wasn't really a clear place to put these. On top of that, I wanted there to be a clear place in the tests for describing the behavior of special types, to make it easier to audit and easier to see how a PR for clap-rs#1772 changes things. As part of this effort in organizing these tests, I reduced the number of tests that use special types. This better focuses these tests on the cases they are intending to cover, rather than pulling in unrelated features. This makes it easier to audit special types and makes it so failures give more focused results, making it easier to see what broke.
Before: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple values, optional - `Option<Vec<_>>`: multiple values, min values of 1, optional After: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple occurrences, optional - optional: `Vec` implies 0 or more, so should not imply required - `Option<Vec<_>>`: multiple occurrences, optional - optional: Use over `Vec` to detect when no option being present when using multiple values Motivations: My priorities were: 1. Are we getting in the users way? 2. Does the API make sense? 3. Does the API encourage best practices? I was originally concerned about the lack of composability with `Option<Option<_>>` and `Option<Vec<_>>` (and eventually `Vec<Vec<_>>`). It prescribes special meaning to each type depending on where it shows up, rather than providing a single meaning for a type generally. You then can't do things like have `Option<_>` mean "required argument with optional value" without hand constructing it. However, in practice the outer type correlates with the argument occurrence and the inner type with the value. It is rare to want the value behavior without also the occurrence behavior. So I figure it is probably fine as long as people can set the flags to manually get the behavior they want. `Vec<_>` implies multiple occurrences, rather than multiple values. Anecdotally, whenver I've used the old `Arg::multiple`, I thought I was getting `Arg::multiple_occurrences` only. `Arg::multiple_values`, without any bounds or delimeter requirement, can lead to a confusing user experience but isn't a good default for these. On top of that, if someone does have an unbounded or a delimeter multiple values, they are probably also using multiple occurrences. `Vec<_>` is optional because a `Vec` implies 0 or more, so we stick to the meaning of the rust type. `Option<Vec<_>>` ends up matching `Vec<_>` which an raise the question of why have it. Some users might prefer the type. Otherwise, this is so users can no when the argument is present or not when using `min_values(0)`. Rather than defining an entire policy around this and having users customize it, or setting `min_values(0)` without the rest of a default policy, this gives people a blank slate to work from. Another option would have been to not infer a setting if someone sets a handful of settings manually, which would have avoided the confusion in Issue clap-rs#2599 but I see that being confusing (for someone who knows the default, they will be expecting it to be additive; which flags?) and brittle (as flags are added or changed, how do we ensure we keep this up?) Tests were added to ensure we support people customizing the behavior to match their needs. This is not solving: - `Vec<Vec<_>>`, see clap-rs#2924 - `(T1, T2)`, `Vec<(T1, T2)>`, etc, see clap-rs#1717 Fixes clap-rs#1772 Fixes clap-rs#2599 See also clap-rs#2195
Before: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple values, optional - `Option<Vec<_>>`: multiple values, min values of 0, optional After: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple occurrences, optional - optional: `Vec` implies 0 or more, so should not imply required - `Option<Vec<_>>`: multiple occurrences, optional - optional: Use over `Vec` to detect when no option being present when using multiple values Motivations: My priorities were: 1. Are we getting in the users way? 2. Does the API make sense? 3. Does the API encourage best practices? I was originally concerned about the lack of composability with `Option<Option<_>>` and `Option<Vec<_>>` (and eventually `Vec<Vec<_>>`). It prescribes special meaning to each type depending on where it shows up, rather than providing a single meaning for a type generally. You then can't do things like have `Option<_>` mean "required argument with optional value" without hand constructing it. However, in practice the outer type correlates with the argument occurrence and the inner type with the value. It is rare to want the value behavior without also the occurrence behavior. So I figure it is probably fine as long as people can set the flags to manually get the behavior they want. `Vec<_>` implies multiple occurrences, rather than multiple values. Anecdotally, whenver I've used the old `Arg::multiple`, I thought I was getting `Arg::multiple_occurrences` only. `Arg::multiple_values`, without any bounds or delimeter requirement, can lead to a confusing user experience but isn't a good default for these. On top of that, if someone does have an unbounded or a delimeter multiple values, they are probably also using multiple occurrences. `Vec<_>` is optional because a `Vec` implies 0 or more, so we stick to the meaning of the rust type. `Option<Vec<_>>` ends up matching `Vec<_>` which an raise the question of why have it. Some users might prefer the type. Otherwise, this is so users can no when the argument is present or not when using `min_values(0)`. Rather than defining an entire policy around this and having users customize it, or setting `min_values(0)` without the rest of a default policy, this gives people a blank slate to work from. Another option would have been to not infer a setting if someone sets a handful of settings manually, which would have avoided the confusion in Issue clap-rs#2599 but I see that being confusing (for someone who knows the default, they will be expecting it to be additive; which flags?) and brittle (as flags are added or changed, how do we ensure we keep this up?) Tests were added to ensure we support people customizing the behavior to match their needs. This is not solving: - `Vec<Vec<_>>`, see clap-rs#2924 - `(T1, T2)`, `Vec<(T1, T2)>`, etc, see clap-rs#1717 Fixes clap-rs#1772 Fixes clap-rs#2599 See also clap-rs#2195
Before: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple values, optional - `Option<Vec<_>>`: multiple values, min values of 0, optional After: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple occurrences, optional - optional: `Vec` implies 0 or more, so should not imply required - `Option<Vec<_>>`: multiple occurrences, optional - optional: Use over `Vec` to detect when no option being present when using multiple values Motivations: My priorities were: 1. Are we getting in the users way? 2. Does the API make sense? 3. Does the API encourage best practices? I was originally concerned about the lack of composability with `Option<Option<_>>` and `Option<Vec<_>>` (and eventually `Vec<Vec<_>>`). It prescribes special meaning to each type depending on where it shows up, rather than providing a single meaning for a type generally. You then can't do things like have `Option<_>` mean "required argument with optional value" without hand constructing it. However, in practice the outer type correlates with the argument occurrence and the inner type with the value. It is rare to want the value behavior without also the occurrence behavior. So I figure it is probably fine as long as people can set the flags to manually get the behavior they want. `Vec<_>` implies multiple occurrences, rather than multiple values. Anecdotally, whenever I've used the old `Arg::multiple`, I thought I was getting `Arg::multiple_occurrences` only. `Arg::multiple_values`, without any bounds or delimiter requirement, can lead to a confusing user experience and isn't a good default for these. On top of that, if someone does have an unbounded or a delimiter multiple values, they are probably also using multiple occurrences. `Vec<_>` is optional because a `Vec` implies 0 or more, so we stick to the meaning of the rust type. `Option<Vec<_>>` ends up matching `Vec<_>` which an raise the question of why have it. Some users might prefer the type. Otherwise, this is so users can no when the argument is present or not when using `min_values(0)`. Rather than defining an entire policy around this and having users customize it, or setting `min_values(0)` without the rest of a default policy, this gives people a blank slate to work from. Another option would have been to not infer a setting if someone sets a handful of settings manually, which would have avoided the confusion in Issue clap-rs#2599 but I see that being confusing (for someone who knows the default, they will be expecting it to be additive; which flags?) and brittle (as flags are added or changed, how do we ensure we keep this up?) Tests were added to ensure we support people customizing the behavior to match their needs. This is not solving: - `Vec<Vec<_>>`, see clap-rs#2924 - `(T1, T2)`, `Vec<(T1, T2)>`, etc, see clap-rs#1717 Fixes clap-rs#1772 Fixes clap-rs#2599 See also clap-rs#2195
Before: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple values, optional - `Option<Vec<_>>`: multiple values, min values of 0, optional After: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple occurrences, optional - optional: `Vec` implies 0 or more, so should not imply required - `Option<Vec<_>>`: multiple occurrences, optional - optional: Use over `Vec` to detect when no option being present when using multiple values Motivations: My priorities were: 1. Are we getting in the users way? 2. Does the API make sense? 3. Does the API encourage best practices? I was originally concerned about the lack of composability with `Option<Option<_>>` and `Option<Vec<_>>` (and eventually `Vec<Vec<_>>`). It prescribes special meaning to each type depending on where it shows up, rather than providing a single meaning for a type generally. You then can't do things like have `Option<_>` mean "required argument with optional value" without hand constructing it. However, in practice the outer type correlates with the argument occurrence and the inner type with the value. It is rare to want the value behavior without also the occurrence behavior. So I figure it is probably fine as long as people can set the flags to manually get the behavior they want. `Vec<_>` implies multiple occurrences, rather than multiple values. Anecdotally, whenever I've used the old `Arg::multiple`, I thought I was getting `Arg::multiple_occurrences` only. `Arg::multiple_values`, without any bounds or delimiter requirement, can lead to a confusing user experience and isn't a good default for these. On top of that, if someone does have an unbounded or a delimiter multiple values, they are probably also using multiple occurrences. `Vec<_>` is optional because a `Vec` implies 0 or more, so we stick to the meaning of the rust type. At least for me, I also rarely need a required with multiple occurrences argument but more often need optional with multiple occurrences. `Option<Vec<_>>` ends up matching `Vec<_>` which an raise the question of why have it. Some users might prefer the type. Otherwise, this is so users can no when the argument is present or not when using `min_values(0)`. Rather than defining an entire policy around this and having users customize it, or setting `min_values(0)` without the rest of a default policy, this gives people a blank slate to work from. Another option would have been to not infer a setting if someone sets a handful of settings manually, which would have avoided the confusion in Issue clap-rs#2599 but I see that being confusing (for someone who knows the default, they will be expecting it to be additive; which flags?) and brittle (as flags are added or changed, how do we ensure we keep this up?) Tests were added to ensure we support people customizing the behavior to match their needs. This is not solving: - `Vec<Vec<_>>`, see clap-rs#2924 - `(T1, T2)`, `Vec<(T1, T2)>`, etc, see clap-rs#1717 Fixes clap-rs#1772 Fixes clap-rs#2599 See also clap-rs#2195
Before: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple values, optional - `Option<Vec<_>>`: multiple values, min values of 0, optional After: - `bool`: a flag - `Option<_>`: not required - `Option<Option<_>>` is not required and when it is present, the value is not required - `Vec<_>`: multiple occurrences, optional - optional: `Vec` implies 0 or more, so should not imply required - `Option<Vec<_>>`: multiple occurrences, optional - optional: Use over `Vec` to detect when no option being present when using multiple values Motivations: My priorities were: 1. Are we getting in the users way? 2. Does the API make sense? 3. Does the API encourage best practices? I was originally concerned about the lack of composability with `Option<Option<_>>` and `Option<Vec<_>>` (and eventually `Vec<Vec<_>>`). It prescribes special meaning to each type depending on where it shows up, rather than providing a single meaning for a type generally. You then can't do things like have `Option<_>` mean "required argument with optional value" without hand constructing it. However, in practice the outer type correlates with the argument occurrence and the inner type with the value. It is rare to want the value behavior without also the occurrence behavior. So I figure it is probably fine as long as people can set the flags to manually get the behavior they want. `Vec<_>` implies multiple occurrences, rather than multiple values. Anecdotally, whenever I've used the old `Arg::multiple`, I thought I was getting `Arg::multiple_occurrences` only. `Arg::multiple_values`, without any bounds or delimiter requirement, can lead to a confusing user experience and isn't a good default for these. On top of that, if someone does have an unbounded or a delimiter multiple values, they are probably also using multiple occurrences. `Vec<_>` is optional because a `Vec` implies 0 or more, so we stick to the meaning of the rust type. At least for me, I also rarely need a required with multiple occurrences argument but more often need optional with multiple occurrences. `Option<Vec<_>>` ends up matching `Vec<_>` which can raise the question of why have it. Some users might prefer the type. Otherwise, this is so users can detect whether the argument is present or not when using `min_values(0)`. Rather than defining an entire policy around this and having users customize it, or setting `min_values(0)` without the rest of a default policy, this gives people a blank slate to work from. Another design option would have been to not infer any special-type settings if someone sets a handful of settings manually, which would have avoided the confusion in Issue clap-rs#2599 but I see that being confusing (for someone who knows the default, they will be expecting it to be additive; which flags disable inferred settings?) and brittle (as flags are added or changed, how do we ensure we keep this up?). Tests were added to ensure we support people customizing the behavior to match their needs. This is not solving: - `Vec<Vec<_>>`, see clap-rs#2924 - `(T1, T2)`, `Vec<(T1, T2)>`, etc, see clap-rs#1717 - `Vec<Option<_>>` and many other potential combinations Fixes clap-rs#1772 Fixes clap-rs#2599 See also clap-rs#2195
Before:
After:
Motivations: My priorities were:
I was originally concerned about the lack of composability with
Another design option would have been to not infer any special-type Tests were added to ensure we support people customizing the behavior to For now, I am leaving off:
To see this in action, see #2993 |
Something like #2993 was recently merged, along with a new derive reference. |
@epage Are we tracking this somewhere? I couldn't find any issue about this since we closed this one. |
Not yet but I think we should wait until there are users asking for them. |
This is actually a summary of TeXitoi/structopt#364
Current behavior
Vec<T>
andOption<Vec<T>>
are notrequired = true
by default.Vec<T>
ismultiple = true
by default which allows not only multiple values (--foo 1 2 3
) but also multiple occurrences (--foo 1 --foo 2 3
).Option<Vec<T>>
additionally allows zero number of values (--foo
).What's wrong
Vec<T>
is notrequired
by default is inconsistent with all the other types inclap_derive
that are required by default unless they are wrapped inOption
(exceptbool
but it's a very special case).Option<Vec<T>>
is different fromVec<T>
, different not in "not required" sense, confuses newcomers.Vec<T>
allows multiple occurrences along with values is misleading.Proposal
min_values = 1
for bothOption<Vec<T>>
andVec<T>
instead ofmultiple = true
, allowing only non-zero number of values and disallow multiple occurrences (--foo 1 2
but not--foo
nor--foo 1 --foo 2
). If a user wants to allow zero values or multiple occurrences as well, they can explicitly specify it viamin_values = 0
andmultiple = true
respectively.required = true
forVec<T>
.cc @TeXitoi @Dylan-DPC @pksunkara
The text was updated successfully, but these errors were encountered: