Currently, there's no easy way to turn a Result<T,E> into a Result<E,T>. We'd like to propose using Not for this, as it's currently used for both negating conditions and bitwise not: true turns to false, 0 turns to -1. It makes sense to have it turn Ok into Err.
I strongly disagree with using an operator for this. The question is whether we want a method for this. Given the fact that Result
already has a bunch of methods, and people that really want something like this can (and have) use(d) extension traits, this might be a bad idea, too, but it’s reasonable to discuss this (and it possibly already has been discussed, who knows). Result is supposed to have a distinction between the error and the non-error case. For something more symmetrical than Result
one could use something like Either
(which has as flip
method). One can also use .map_or_else(Ok, Err)
which really isn’t all that long.
sometimes you want to invert a result similar to how you invert a condition or a flag. and as we do have Not on bools (and on numbers), it makes sense to extend the Not-ness of bools to Result, which is intended as a replacement for bools.
Given that there’s not even a method for this yet, I don’t think that the need for this kind of operation is common enough to warrant the use of the !
operator.
Also, I’d be interested in seeing a realistic use-case that isn’t covered equally well by something like pattern matching, err()
or is_err()
. I do admit that a .map_or_else(Ok, Err)
call looks a bit confusing and some new method called something like .flip()
might be more clear.
ppl didn't like us using bools everywhere and having a macro for doing ?
on bools, but with bools you can use !
but you can't do the same with Result so bools are superior.
(and making the bry!
macro isn't too bad considering we had the try!
macro for ages.)
- For a method to do this, please provide some real world use cases for when one wants to invert a
Result
. - For operator support via impl'ing the
Not
trait, please do (1) and show that this usage is common enough to warrant operator support for it.
Result
is designed for error handling. While negation may exist strictly algebraic, in practice, I doubt negation is common or useful. Usually the Err
variant has additional trait bounds that make it specifically useful for error handling that the Ok
variant doesn't.
Speaking as a library team memeber, instead of arguing about abstractions and what "makes sense" from a vague consistency/theoretical perspective, please provide concrete usages that motivate the additions proposed.
when we asked for try on bools nobody wanted it, so now we want not on result to get the same effect.
parsing is a pain. it makes sense to want inversion of failure.
Yet this is the first clue you've given for what problem you're trying to solve.
I suspect this might be better served by a custom wrapper when Try
is stabilized, so you can shortcut your desired case. The current redesign also proposes an enum ControlFlow
that might work for you.
what churn is there in adding Not to Result?
I could ask that about any number of things; it's not a valid reason to do something on its own. You haven't shown where this would be objectively clearer in most situations. If I ran across someone negating a Result
in a code review, I'd immediately reject it in favor of something that has obvious behavior.
Let's say you have a Result<(&str, &str), &str>
, as coming from a lexer. It makes sense to fail if a token matches, so then you want to (!result.map(HelpfulError))?
or (!result).map_err(HelpfulError)?
. Alternatively you need to make your lexer take an &mut &str
(not to be confused with &mut str
) and output bools and use bools everywhere, which is, in fact, a lot easier than trying to work with the existing Result
.
The "ideal" lexer API is fn(&str) -> Option<usize>
(for a single token kind) or fn(&str) -> Option<(Kind, usize)>
(for any kind in a set). This just handles the needed information, and no more. Optionally, bake "unknown" into the token Kind
and skip blocks of unrecognized input together.
Part of the API that makes a lexer a lexer is that it doesn't have rich errors. You just try all the cases and return the one that matches (or the longest match if you don't have a "perfect" lexical grammar).
If you take &str
, there's no need to return the input back on failure, because it's already just borrowed.
For a new feature, you need to motivate it in some manner. What problem does it solve? Why don't current language features serve it well enough?
You consistently fail to provide motivation for your suggestions beyond some implication of "it would be nice", leaving the rest of us to guess at what you're trying to do. Please, while you don't have to follow the RFC template exactly on IRLO, provide some motivation for your suggestions. Nobody else knows what you're running into.
but having the input back is nice because you can just chain the things, either with and_then
/or_else
or with foo(bar(baz)?)?
or whatnot.
these Try-related suggestions (beside the one about Try-on-bool, which we already use with a bry!
macro everywhere) would take about as much effort as rewriting our parsers from scratch if we wanted to provide real examples.
Please explain how it's clearer, which is what I asked. Think of how you'd explain this to a newcomer to Rust, not an experienced person. While the parsers I've written don't follow the pattern you've shown, I understand that some do. I'm not asking about utility, I'm asking about clarity. Consider that the RFC-proposed Try
trait would let you do this, as well.
It seems clear that implementing Not
doesn't really fit. Is there any opposition to a flip
method?
impl<T, E> Result<T, E> {
fn flip(self) -> Result<E, T> {
match self {
Ok(t) => Err(t),
Err(e) => Ok(e),
}
}
}
I think mostly from a philosophical point of view. Where having this sort of method seems like you are abusing result to be a generic ether type.
I think this equivalent to result.err().ok_or(HelpfulError)?
This little detour through Option
for such a niche case seems reasonable.
Well, there might be cases where you want an error to happen. That's the reason why unwrap_err
exists.
unwrap_err
panics if the Result is Ok, but there is no function that returns an error if the Result is Ok.
If we never had Result in the language it'd be possible to experiment with API design for it. Too bad trait impls are insta-stable because we feel like this is something that would heavily benefit from experimentation.
At least parsers would be able to take benefit from it.
That isn't what is being asked for here though. That could very well be added behind a feature gate. Or even a new topic. Though I think Inline error recovery - #16 by steffahn is basically what is being asked for here anyway.