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.
I'm looking forward to the next editions: one to deprecate, one to remove.
That would also soften the controversy.
@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 Deprecating unwrap would be something for the next rust edition?
I’d happily adapt some old code.
#[deprecated] for an extremely long time and would only actually get removed in an edition change.@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.
@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

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 ...
@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.
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 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()
unwrap_or_panic, this is a good idea@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 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
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)@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.