Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
Posted Sep 24, 2025 18:02 UTC (Wed) by epa (subscriber, #39769)Parent article: Canceling asynchronous Rust
Maybe the problem is that Future doesn't get special treatment in the type system. The await method returns the underlying value, but you don't have to await. Perhaps there should be a special syntax for "do not await" -- which obviously just returns the Future itself -- and a linter or compiler warning could ensure that you have called one or the other. If the type is known at compile time to be a Future of some kind, the let _ syntax would give a compile-time warning, unless you explicitly call .do_not_await.
Posted Sep 24, 2025 18:45 UTC (Wed)
by daroc (editor, #160859)
[Link]
That is somewhat similar to what the Undroppable Types proposal would do, only not specific to Futures. With that proposal, any type marked as being Undroppable would be a compiler error to discard, including via let _ = .... The only ways to get rid of it would be by consuming it (in this case, doing .await), handing it off to another function, or by destructuring it.
Posted Sep 24, 2025 20:20 UTC (Wed)
by duelafn (subscriber, #52974)
[Link] (1 responses)
That particular situation has a (disabled by default) lint: clippy::let_underscore_untyped. Gets a warning "consider adding a type annotation" which goes away if you do this: Which would catch the async problem. I go one step further and make sure the Ok result type is also specified (
Posted Sep 25, 2025 11:22 UTC (Thu)
by kpfleming (subscriber, #23250)
[Link]
Posted Sep 24, 2025 21:25 UTC (Wed)
by NYKevin (subscriber, #129325)
[Link] (2 responses)
We already have a lint warning for dropping something that shouldn't be dropped, namely #[must_use], which is present on Futures. Clippy will warn you if you write an expression statement that implicitly drops a Future (and you can configure this lint to be deny-by-default if desired, so that it produces a hard compile error instead of a warning). The let _ syntax is the idiomatic way to silence that lint, so you're effectively proposing a second "no, I really mean it" syntax, to doubly silence the warning after it has already been silenced. I'm not sure why that would be any more effective than the existing lint is in isolation. There is, perhaps, some room for marginal improvement, since #[must_use] is quite liberal about what counts as a "use," and a Future-specific warning could be more exacting. But this seems to be well into diminishing returns relative to the increased language complexity.
If we think that #[must_use] is not sufficient, then I must concur with daroc: The logical next step is undroppable types, not another layer of "no, I really mean it" syntax. Undroppable types let us make hard assertions that you *must* dispose of an instance in the appropriate way.
We might also consider unforgettable (a/k/a unleakable) types, but I think it is much less common to accidentally leak an object than to accidentally drop an object (you either have to construct a refcounted cycle, or use an interface that "obviously" leaks, such as std::mem::forget or Box::leak). Those are only needed if you want to prohibit leaking objects as a safety invariant. In other words, you need them for cases where leaking an object could produce UB. That's pretty unusual, and the only obvious example I can think of is the original (now known to be unsound) API for std::thread::scope. But the new API does not need unleakables, and it was a fairly minor change, so this is not a great motivating use case for them.
Posted Sep 25, 2025 4:52 UTC (Thu)
by mb (subscriber, #50428)
[Link]
async fn a() -> Result<x, y> {
async fn b() {
It would be good if the first thing caused a warning by default. It's a common mistake.
Posted Sep 25, 2025 6:08 UTC (Thu)
by epa (subscriber, #39769)
[Link]
Posted Sep 25, 2025 8:11 UTC (Thu)
by proski (subscriber, #104)
[Link] (2 responses)
Posted Sep 25, 2025 8:57 UTC (Thu)
by taladar (subscriber, #68407)
[Link] (1 responses)
Posted Sep 25, 2025 21:26 UTC (Thu)
by intgr (subscriber, #39733)
[Link]
Posted Sep 25, 2025 13:51 UTC (Thu)
by Brezak (subscriber, #174007)
[Link]
Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
let _ = some_operation();
let _: Result<_,_> = some_operation();
Result<u64,_>
, but the lint does not enforce that.Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
...
}
// Ignore the Result of a().
let _ = a(); // What I wrote
let _ = a().await; // What I meant
}
Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
Discarding return value, and ignoring return type
There's the clippy lint clippy::let_underscore_future, that stops you if you discard a future without awaiting it. It's even warn by default.
Discarding return value, and ignoring return type