Should the `+ a` in `-> impl Opaque + 'a` be deprecated
⚓ Rust 📅 2025-10-28 👤 surdeus 👁️ 4In the following article, Niko describes this example:
fn process<'c, T> {
context: &'c Context,
data: Vec<T>,
) -> impl Iterator<Item = ()> + 'c {
data
.into_iter()
.map(|datum| context.process(datum))
}
He explains:
Here the
processfunction appliescontext.processto each of the elements indata(of typeT). Because the return value usescontext, it is declared as+ 'c. Our real goal here is to allow the return type to use'c; writing+ 'cachieves that goal because'cnow appears in the bound listing. However, while writing+ 'cis a convenient way to make'cappear in the bounds, also means that the hidden type must outlive'c.
The last clause caught my attention.
'aappear in the bounds, also means that the hidden type must outlive'a
In type bound terminology, this translates to: "The opaque type cannot contain references shorter than 'c" (i.e., T: 'c).
Revisiting an Earlier Discussion
I posted about this 3-6 months ago and learned a lot from the discussion, even if I didn't convince anyone! After revisiting the discussion and tweaking the claim, I think the following explains the tension that I can't seem to explain away.
The Fundamental Ambiguity of + 'a in Rust 2024
The Core Problem
+ 'a on return types creates the bound T: 'a, which states: "T cannot contain references shorter than 'a."
But the borrow checker already makes this impossible.
Why the Bound Is Nonsensical - there is no useful intent
Single Lifetime Case
fn foo<'a>(x: &'a str) -> impl Display + 'a {
// What references shorter than 'a not already prevented by the borrow-checker can live here?
}
The bound + 'a enforces a constraint that cannot be violated. It's like writing:
fn add(x: u32, y: u32) -> u32
where u32: Copy // ← Always true, completely redundant
Multi-Lifetime Case
fn foo<'a, 'b>(x: &'a str, y: &'b str) -> impl Display + 'a {
// The + 'a prevents using y when 'b < 'a
}
Here + 'a does constrain something—but why would you want this?
- If you don't need
'b, don't usey - If you do need both lifetimes, the constraint just gets in your way
- The bound doesn't prevent bugs; it enforces an arbitrary restriction
The Ambiguity
+ 'a conflates two orthogonal concepts:
- Capture: "Make
'aavailable to the hidden type" (what you actually need) - Bound: "Constrain away shorter lifetimes" (redundant or restrictive)
Before use<>, you had no choice—you needed + 'a for capture.
After use<>, the bound becomes pure noise that:
- Pretends to add a constraint that's already impossible to violate
- Or artificially restricts valid implementations
- Obscures the actual intent (capture)
The Succinct Argument
The world where + 'a has meaning is a world where you could return references shorter than 'a. But the borrow checker makes this world impossible. Therefore, + 'a either enforces nothing (single lifetime) or enforces an arbitrary restriction (multiple lifetimes). In Rust 2024, use<'a> clearly expresses capture without the nonsensical bound semantics.
In my estimation, for new code, + 'lifetime should be considered deprecated in favor of use<>.
What do others think? Am I missing something? Does anyone have an example of where they needed + 'a in the return type, using the 2024 edition?
3 posts - 3 participants
🏷️ Rust_feed