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
unwrap!
-everything
#127
Comments
The new let PatternElement::Tag { key_subtree } = frame.op() else {
unreachable!()
};
// use `key_subtree`... which should reduce the need for something like this a lot. |
There's also the crate enum-as-inner which I believe would allow (for
(or something similar, my apologies if this is not 100% correct, I'm not looking in detail at the docs for the crate right now) |
do any of those produce the nice panic messages that (which, fwiw, is better than what we have with |
What exactly would |
using while we don't exactly want the value after the |
Something like this? macro_rules! unwrap {
($pattern:pat_param = $expression:expr) => {
let $pattern = $expression else {
panic!("unwrap failed: {}", stringify!($pattern = $expression));
};
}
} Silly example (playground): fn main() {
let mut opt = Some(10);
loop {
unwrap!(Some(x @ 2..) = opt);
dbg!(x);
let y = if x % 2 == 0 { x / 2 } else { 3 * x + 1 };
opt = Some(y);
}
}
|
yes, tho we'd also like expression/value functionality (tho that's way harder ofc). |
How do you expect to see the value if you don't have |
no like |
Ah -- I think we'd need a compiler builtin to extract arbitrary bindings from a pattern. |
Additional benefit of assert!(self.interp.frames[target].prev()); // bad
self.interp.frames[target].prev().then(|| ()).unwrap(); // awkward but okay
unwrap!(true = self.interp.frames[target].prev()); // perfect |
How about just throwing most the unwrapping methods on trait Try: FromResidual<Self::Residual> {
// ...
fn unwrap(self) -> Self::Output {
// Ideally, this would use some compiler magic to wire in the type name instead.
match self.branch() {
ControlFlow::Break(_) => panic!("called `Try::unwrap()` on a residual value"),
ControlFlow::Continue(result) => result,
}
}
fn unwrap_or_default(self) -> Self::Output where Self::Output: Default {
match self.branch() {
ControlFlow::Break(_) => Self::Wrapped::default(),
ControlFlow::Continue(result) => result,
}
}
fn unwrap_or(self, default: Self::Output) -> Self::Output {
match self.branch() {
ControlFlow::Break(_) => default,
ControlFlow::Continue(result) => result,
}
}
unsafe fn unwrap_unchecked(self) -> Self::Output {
match self.branch() {
ControlFlow::Break(_) => std::hint::unreachable_unchecked(),
ControlFlow::Continue(result) => result,
}
}
fn expect(self, msg: &str) -> Self::Output {
match self.branch() {
ControlFlow::Break(_) => panic!("{}", msg),
ControlFlow::Continue(result) => result,
}
}
fn map_or<U>(self, default: U, f: FnOnce(Self::Output) -> U) -> U {
match self.branch() {
ControlFlow::Break(_) => default,
ControlFlow::Continue(result) => f(result),
}
}
fn map_or_default<U: Default>(self, f: FnOnce(Self::Output) -> U) -> U {
match self.branch() {
ControlFlow::Break(_) => U::default(),
ControlFlow::Continue(result) => f(result),
}
}
}
impl<T> Try for Option<T> {
// ...
fn unwrap(self) -> Self::Output {
self.expect("called `Option::unwrap()` on a `None` value")
}
}
impl<T, E> Try for Result<T, E> {
// ...
fn unwrap(self) -> Self::Output {
self.expect("called `Result::unwrap()` on an `Err` value")
}
fn expect(self, msg: &str) -> Self::Output {
// Do this for `E: fmt::Debug` and just the default for other types
// match self {
// Err(e) => panic!("{}: {}", msg, e),
// Ok(result) => result,
// }
SpecExpect::expect(self, msg)
}
} This would merge large chunk of This does carry a major con, though: it'd make rust-lang/rust#67441 depend on traits supporting const fns (in some capacity). |
|
We discussed this in a libs meeting. While we do want to make traversal of data structures and patternmatching less cumbersome we have several blocking concerns about this particular proposal and thus are going to close it.
|
Proposal
Problem statement
Maybe you wanna unwrap a
Result
withoutDebug
, or a custom type that doesn't even represent an error but maybe represents a state machine and you wanna assume you're in a specific state and grab the values inside of it. Theunwrap!
-everything API would allow exactly that.Motivation, use-cases
We wrote this like 5 times before making it a function:
And we have... multiple places where we use this exact pattern.
Solution sketches
We'd like to see some sort of
unwrap!
macro which basically asserts the expectation and returns the relevant results:Tho we acknowledge we haven't thought about how this would interact with multiple results like so:
Maybe it should look more like this instead?
Links and related work
https://doc.rust-lang.org/std/index.html?search=unwrap
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
The text was updated successfully, but these errors were encountered: