or similar. With impl From<T> for Option<T>, you’d be able to call it as
myfn(0, None, 2)
which removes a lot of noise at the call site. The definition of myfn would gain some noise:
fn myfn(t: T, u: U, v: V) -> Option
where T: Into<Option<u8>>,
U: Into<Option<u8>>,
V: Into<Option<u8>>;
However, I think that pushing the noise into the definition makes for nicer user code overall.
I feel like this is an obvious impl, and so there must be a good reason it’s not already in std. Am I missing something? Should I just make a PR from this commit?
That’s difficult when you’re asking me to demonstrate the real-world problems with a non-existent feature.
My point is that this would mean what x does depends on what the inferred type is; in some cases it would pass through directly, in others it would wrap in a Some. I mean, if you say None in the source, did you mean no value, or Some(None)?
Thankfully, it wouldn’t be as bad as null or Python-esque None, but it still seems a needless complication.
I think that, if you want optional arguments, they should be a language feature.
(Now, implementing Extend on Option, that makes perfect sense…)
In real world, there isnt much use of having Option as a function argument, because you usually only really care about the Some case. If you only care about the Some case, dont use Option, and just use T!
If you want optional arguments, I dont think shoehorning them in this way is a good idea.
The various IO types have set_{read,write}_timeout methods that take Option<Duration> and invocations of them could be cleaned up by this kind of change.
My impression of std::convert::From and std::convert::Into is that they change the “representation” of things but not the “meaning” of things, where to me, T and Option<T> are quite different in meaning.
Can you think of a problem with this feature that does not rely on the (highly) unrealistic type Option<Option<T>>? It seems silly to abandon a feature which only malfunctions in this particular corner case.
It can be patched by adding a meta-trait Definite which is possessed by every type except Option (I’m not sure if the language allows this) and then writing impl From<T> for Option<T> where T: Definite. This covers approximately every situation the original proposal does, because optional options are pretty rare.
I don’t know if I agree with Option<Option<T>> to be unrealistic. E g, a message handler might give back None if the message was not handled at all, Some(None) if the message was handled but did not require a reply, or Some(Some(Reply)) if there was a reply.
Conceptually, the default value should go with the parameter not its type. With this setup, every default value requires its own data type. This is a lot of typing (both kinds) and I don’t think it puts ideas in the right place. Compare:
// Adding trait for demo because I can't implement write the blanket Into
// or From impl necessary.
trait IntoOption<T> {
fn into_option(self) -> Option<T>;
}
impl<T> IntoOption<T> for Option<T> {
fn into_option(self) -> Option<T> {
self
}
}
impl<T> IntoOption<T> for T {
fn into_option(self) -> Option<T> {
Some(self)
}
}
fn example<T, U, V, W>(t: T, u: U, v: V, w: W) -> i32
where T: IntoOption<i32>,
U: IntoOption<i32>,
V: IntoOption<i32>,
W: IntoOption<i32>
{
let t = t.into_option().unwrap_or(0);
let u = u.into_option().unwrap_or(0);
let v = v.into_option().unwrap_or(0);
let w = w.into_option().unwrap_or(40);
t + u + v + w
}
fn main() {
println!("{:?}", example(10, 20, None, None));
}
I have been thinking recently about the same thing. My conclusion was that my need for such feature goes away if there is a way to specify default values for parameters.
I don’t think that C++ style default parameter values will fit well in Rust. We don’t have overloading except via traits, while C++ already allowed type and argument number overloads.