#rustlang hot take: We should rename .unwrap() to .or_panic(). (And .expect() to .or_panic_with().) "Unwrap" is a terrible name for the panicking function, especially since we also have things like .unwrap_or() and .unwrap_or_default() which never panic.
(That the name "or_panic" would have been better isn't much of a hot take, but adding "or_panic()" now and deprecating "unwrap()" would likely be controversial.)
I think it would be fine but the deprecation lint would have to start being enforced in next edition and I don't think .unwrap*() could be truly deprecated for the next few editions

@Mara
@pj @Mara why? Deprecated != removed 😂 Seems perfectly reasonable to me to introduce a new API with a deprecation on the old one. It’s probably even auto-fixable with clippy.

@ianthetechie @pj @Mara

A simple renaming is the singular thing that `#[deprecated(suggestion = "foo")]` can handle, so it doesn't even need clippy!

@pj @Mara what about a lint that force every line that could panic to be preceded by a `// PANIC:` comment block, like the one for unsafe:

https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks

If they can panic. And if they can't: `#[expect(clippy::missing_panics_doc, reason = "infallible")]`

https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc

That way, any panic hidden in a function call should become visible.

Clippy Lints

A collection of lints to catch common mistakes and improve your Rust code.

@Mara I have done it in some projects via a trait in the prelude and enabling the lints to forbid unwrap: https://github.com/beeb/awsbck/blob/main/src%2Fprelude.rs

@Mara

I'm looking forward to the next editions: one to deprecate, one to remove.
That would also soften the controversy.

@Mara I don't see why this would be controversial? It would make things much more clear and consistent. Adding this as a deprecation, with an auto fix upon removal would be great.

@Mara or make

unwrap -> unwrap_or_panic
unwrap_or_default -> unwrap

But this probably crashes with legacy code.

@Mara This could totally be done if done very slowly IMO.

eg: Start by adding a feature that makes deprecation warnings show only once for an entire class of function per codebase, have that turned off by default, allow it to be disabled per-crate in Cargo.toml.

Turn it on in nightlies for a bit, wait a few months. Patches should start to flow into upstream crates to fix those warnings.

Wait for the top N% of crates on crates.io to be fixed, roll it out to beta and then stable.

Plan on doing this over 2-3 years.

@Mara (this is me speaking both as a crate author and consumer - I don't think it would be too onerous at all)

@Mara Deprecating unwrap would be something for the next rust edition?

I’d happily adapt some old code.

@Mara Probably but that doesn’t mean we still shouldn’t do it. Though it would probably stay #[deprecated] for an extremely long time and would only actually get removed in an edition change.
@Mara I think we should not solve the problems of people who didn't read the Book 😁
If comment seriously, not sure that changing the name will help here, as this functionality so basic, that no developer would use it without understanding the consequences.
@Mara also in my projects I enable errors for all warning lints, including "unwrap_used". Which I think more than enough to prevent accidentally misusing it.
@Mara this is doubly confusing because in many other languages, even some FP languages, "unwrapping" a value is actually a non-panicing operation lol
@froge Yes, .into_inner() should have been .unwrap().
@Mara minor semantic changes like this can make a big difference for sure
@Mara i remember when learning rust a long time ago this was a bit confusing. expect(), vs unwrap(), vs panic!() vs all the *_or_default(), *_or()...
@Mara
Doesn't help that I'm associating unwrapping with unwrapping presents, and occasionally expecting what's inside. Like a perpetual birthday party.

@Mara yes please! 💯

I had a design where the || and && operators were overloadable, and there, res.unwrap() turned into

res || panic!()

and res.unwrap_or(default_value) into

res || default_value

and res.unwrap_or_else(callback) into

res || callback()

But if you're not doing that, renaming the methods would be great.

@bugaevc How would `res || panic!("oh no")` show the Err value in the panic message? res.unwrap() and res.expect("oh no") both show the Err value.
@Mara @bugaevc probably res || panic!("oh no: {res}"), but that's subjectively not as nice looking
@tauon but `{res}` would be the whole `Result<T, E>`, not just the `E`, right?
@Mara @tauon moreover, that just wouldn't work since we've already moved the `res` into the LHS
@bugaevc @Mara oh of course it wouldn't, you're right
...
&res then ​
@Mara yeah, it should still work but you'd see the Err(…) around it (if you didn't want to you'd have to do .unwrap_err which looks worse and is what we're trying to avoid)
@bugaevc @Mara So... || is just a postfix closure with no `.`, conditionally invoked on the lhs producing a failure value (right now only `false` is supported 😀)

@oli @Mara it's not a closure since it can contain control flow, and also likely do things that borrow checker wouldn't like a closure doing. It was desugared to explicitly query the LHS whether or not to short circuit, and run the RHS if not.

https://internals.rust-lang.org/t/pre-rfc-overload-short-curcuits/10460/29

Pre-RFC: Overload Short Curcuits

So what if it looked like this then, to make it clear that it's not a generic "is truthy" / "bool coercion", and additionally to make it possible to return custom values when short circuiting: enum ShortCircuit<S, L> { Short(S), Long(L), } trait LogicalOr<Rhs = Self>: Sized { type Output; /// Decide whether the *logical or* should short-circuit /// or not based on its left-hand side argument. If so, /// return its final result, otherwise return the value /// that ...

Rust Internals

@Mara
But wouldn't that make the API inconsistent? Since the other or*() methods don't change the type.

I guess there are quite a few Rust methods with innocent sounding names that can panic. clamp() is one I'm always wary of. There's also the ones that allocate memory, like for Vec and String.

#RustLang

@ygor @Mara
On an `Option<T>`, the output type of `unwrap_or_default` is `T`.

The output type of `unwrap_or_panic` would also be `T`.

Or am I missing something?

@tdelmas @Mara yes, unwrap_or_panic() would be consistent, but or_panic() as proposed would not, as it looks like or() and or_else(). The question is, is the problem the "unwrap" terminology, or that it isn't clear enough which methods can panic? Or both?
@Mara how аbout using а much stable language like c++ instead of rust
@balasubramanium Stable? C++ has had more breaking changes over its evolution than Rust. Rust is extremely stable. See the "Stability" section I wrote here: https://blog.m-ou.se/rust-standard/#stability
Do we need a "Rust Standard"?

Languages like C and C++ are standardized. They are fully specified in an internationally recognized standards document. Languages like Python, Swift and Rust do not have such a standards document. Should Rust be standardized? Why, or why not? In this blog post, I try to explain why I do think we need an accurate specification, why I do not think we need “standardization” (depending on your definition), and give an overview of the current state of Rust’s stability and specification efforts.

@Mara
But if you keep writing C++98, then its stable  
@balasubramanium
@Mara Funny timing as I actually came across an unwrap_or() in code yesterday and it took me a few seconds to realize it wasn’t going to panic, really not helpful naming.

@Mara Quite a good suggestion. It makes panicking an intentional outcome rather than an accidental one.

FWIW I don't know if many people liked unwrap(), but they really didn't like Aaron Turon's suggestion of assert()

@timClicks @Mara ehhh i can see why assert makes sense but i think or_panic is nicer
@Mara yeah. the actual thing it does is more like unwrap_or_panic, this is a good idea
@Mara this sounds much more descriptive! But how would it play with the existing .or() and .or_else(), which return another Option/Result? If those didn't exist, then renaming all .unwrap_or_*() to .or_*() would make it all nice and consistent. But those are taken, and keeping .unwrap_or_*() alongside .or_panic() seems to introduce a new inconsistency 🤔
@azymohliad @Mara What about `ok_or_panic`? It's both explicit and a nod to its enum name.
@zimzat @Mara Option::ok_or() and Option::ok_or_else() also exist and return Result.

@azymohliad @zimzat I use `getOrPanic`, along with this naming scheme, which –unlike Rust's– is internally consistent:

https://soc.me/languages/naming-conventions-option-and-result

@soc I like it! @Mara could this actually be a solution for Rust 1.X? All existing .unwrap_*() could be renamed to .get_*(), .unwrap() would become .get_or_panic(), .expect() would be .get_or_panic_with(), Result::unwrap_err() would become .get_err_or_panic(), and it all seems to align well with the existing Option::get_or_insert*().

.unwrap() name would become longer, but maybe it's actually not a bad thing to "increase the price" of panicking? Other `unwrap_*` methods would become shorter!

@Mara @soc ah, never mind, .get_or_insert*()s take &mut self, and .unwrap*()s consume.
@azymohliad Time for Rust 3.0.

@Mara i think it’s a valid take, but counterargument:

say you have a function called parse_input that returns an Option<Parsed>

and we have a part of the code where parse_input is presumed to be infallible, perhaps we’re loading a static file at compile time

doing let parsed = parse_input(MY_STATIC_INPUT).or_panic(), at least to me, feels worse than saying “unwrap” (because we’re expecting a value to be returned here, the focus is the returned value, not the fallibility)

unwrap is what the operation means, but it’s not what the operation is (which is to panic), and you can see i did a cheek-in-tongue argument for expect too (which ties into how you’re “supposed” to format the message, i. e. a “correct” expect reason here might be should be infallible with MY_STATIC_INPUT)

the case is stronger for Result though

@Mara though for expect the case to keep it as-is is doubly strong because of how they end up being shown in a panic message (something something expect isn’t just panicking with the message provided, and my crackpot theory is that they chose the name so people go look up why it’s called expect and learn the reasoning)
@twinkle @Mara To me, this is where “or_panic()” makes the most sense. When I have something which shouldn’t be able to fail and it fails anyway, I want the application to panic because it’s clearly in an unreasonable state.

@Mara I think it's a fantastic idea.

I would also love to see it not encouraged by practically every tutorial out there, especially official ones, as it creates a bad habit that has to be unlearned.

@Mara The naming of "expect" was the worst offender for me. For the few times I use rust, I always forget how its called. I dont expect a function named `expect` to take an error message as input, but rather to evaluate a predicate on the object (think of `32.expect(is_even)`). Naming it `or_panic` would make much more sense.
@Mara I'd even be in favor of .or_abort(), having panic=abort a build configuration and not an API is a misfeature imo (of course .or_panic() could stay as well)
@cehteh @Mara panic=abort should be specified by each crate and a panic=abort crate should not compile as a dependency of a non-(panic=abort) target
@zwarich @cehteh @Mara It was before I started bookmarking anything I thought I might want to refer back to but, unless my memory is faulty, "panic mode is a property of the top-level project (as defined by the binary crate), not individual crates" was an intentional design decision for the sake of encouraging composability, similar to how not allowing type inference in function signatures is an intentional restriction, not a technical limitation.