hello there!
I am always puzzled when I need to do:
matches.value_of("arg_name").unwrap()
when I could just do (if clap supported it)
matches["arg_name"]
I heard clap is going to make a release soon, if there's no opposition to this change, I'll try make a PR!
@pksunkara @CreepySkeleton
Since value_of can be used but also, values_of, which doesnt return the same type, I wonder if it's possible to generically return either of them
which would be either &str or an iterator on &str
Or we could just say that the ergonomic subscript access is always value_of
Generic return values tend to result in less ergonomic code, requiring either type signatures or turbofish.
too bad, would it be acceptable to assume value_of when using array indexing?
Ideally, if moving to a less stringly typed argument handling, the argument type would determine that.
@Josh Triplett I see you've got "deserialize into struct" thing now
I think the biggest problem with the index operator is failability - lack thereof. value[s]_of
can fail (return None) if the arg is not required and user (or default value) didn't provide it.
Come to think of it, a generic returning value might be `Box<dyn Iterator<Item = &str>, I guess.
Although it won't help you much
moving to a less stringly typed argument handling
This topic pops up every so often, but nobody was able to even remotely guess something that could possibly work.
What we're talking about here is heterogeneous container
Clap is, simply speaking, a dictionary (map)
It maps _argument identifier_ to a list of _values_ (&[Os]str)
Identifier is also &str
What users want is to convert the values to the respective types, but types can be anything
There's already value_of_t
that encapsulates this logic
I think this is about as far as we can go without any sort of macros. You can't just have a methods with the signature of &self -> SomeType
because SomeType
will be different for different arguments.
@CreepySkeleton most of the time, I provide default values for my arguments, so in that case, index is fine, but of course, that's the inconvenient of it
I see it's not written in the README, but can't clap also serve as a configuration management library? wouldnt there be interest in also allowing something like yaml configurations to be passed and the yaml config fills the command line arguments?
like a special switch, e.g. --file-arguments /etc/example/example.yaml
There were some discussions about it, but it's not a high priority for us. You could take a look around and contribute to the discussions.
@Leo Le Bouter ArgMatches
doesn't know whether "cfg"
for example has default value or not. Most importantly, we would need this kind in information to be encoded in type system so the index op could distinguish and return either option or the value itself, depending.
But identifiers don't have this kind of type system info attached, it's just &str
Yes, we could add such an impl in addition to value_of
But how to encode the difference between value_of
and value_of_os
in it?
It's vital when it comes to file paths
Actually, when trait impl specialization finally lands, we could do something like:
// The traits are mutually exclusive
trait ClapFromStr: !ClapFromOsStr {
fn from_str(&str) -> Self;
}
trait ClapFromOsStr: !ClapFromStr {
fn from_os_str(&OsStr) -> Self;
}
// everything that requires the argument to be valid utf-8
impl ClapFromStr for &str, String, i64, ...
// everything that doesn't have to be valid UTF-8
impl ClapFromOsStr for Path, PathBuf, ...
// impl that uses value_of
impl<R: ClapFromStr> Index<&str> for R;
// impl that uses value_of_os
impl<R: ClapFromOsStr> Index<&str> for R;
But we need to be able to mark the traits as mutually exclusive.
@CreepySkeleton Cool! Glad to know it's trait impl specialization that helps it!
No wait, we don't need it!
o.o!
ALl we ned is to impl it for the interesting types one by one
like impl for String, u64, Path, etc
But there's another problem
Guess what?
and then matches["test"] returns what?
It returns R
Which should be inferred from context in most cases
okay, interesting
The real problem is that conversion themself can fail
didnt know you could actually return generics from indexing
For example, what if you're trying to convert it to u64
but the value is "foo"?
@CreepySkeleton then macro to the rescue?
???
@CreepySkeleton I mean no indexing, just a macro
We already have that
it's called value_of_t
and it's not a macro
*Will have in 3.0
I... I actually feel enlighten
What if App::arg
took not Arg
but some generic R
that implements ArgTrait
@CreepySkeleton Is it possible to check all accesses of the indexing and do checks at the start of the program for correct types?
with the type system?
or encode the type in the declaration of arguments
I think it might be possible for some number of select types, but not in general
or encode the type in the declaration of arguments
That's what I'm thinking
I need to fork clap and publish my clap-killer arg parser at this point, muhaha!
aha I'm glad!
@CreepySkeleton I would really like a shorthand for .unwrap() on Option
could the *
operator be used as such?
*matches.value_of("test")
?
panics if invalid?
value_of is too long too
val
could be ok
or get
The problem is that it can fail because of two unrelated reasons - the argument wasn't provided and the argument couldn't be parsed as the resulted type.
Should it panic in both cases?
The problem with get
is that the famous slice::get
return Option
I would prefer to follow the example