Should the `+ a` in `-> impl Opaque + 'a` be deprecated

⚓ Rust    📅 2025-10-28    👤 surdeus    👁️ 4      

surdeus

In 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 process function applies context.process to each of the elements in data (of type T). Because the return value uses context, it is declared as + 'c. Our real goal here is to allow the return type to use 'c; writing + 'c achieves that goal because 'c now appears in the bound listing. However, while writing + 'c is a convenient way to make 'c appear in the bounds, also means that the hidden type must outlive 'c.

The last clause caught my attention.

'a appear 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 use y
  • 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:

  1. Capture: "Make 'a available to the hidden type" (what you actually need)
  2. 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

Read full topic

🏷️ Rust_feed