# Eliding higher rank lifetimes in trait bounds

**URL:** <https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861>\
**Category:** Uncategorized\
**Created:** [August 16, 2016, 4:03am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861 "2016-08-16T04:03:43Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [August 16, 2016, 4:03am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/1 "2016-08-16T04:03:43Z")

</div>

```rust
// "Function" trait syntax:
F: Fn(&T) -> T
// Expands to:
for<'a> F: Fn<&'a T, Output = U>

```

Function traits have special sugar to give them an ergonomic and familiar shape, while under the hood they are treated consistently with other traits. This sugar currently combines two steps:

1. It elides higher ranked lifetime parameters; if a lifetime parameter is excluded from the function, it is treated as being higher rank.
2. It converts from the form `Fn(Args..) -> Return` to a more regular form `Fn<Args..., Output = Return>`.

I think it would make sense that the ellision step of this be applied to all trait bounds. That is:

```rust
trait Foo<'a> { }

F: Foo
// is equivalent to
for<'a> F: Foo<'a>

trait Bar<T> { }
B: Bar<&i32>
// is equivalent to
for<'a> B: Bar<&'a i32>

// and so on

```

Reasons:

1. I think that this is very commonly what you want.
2. This is the most general bound and the most restrictive bound. This makes it a sane default.
3. If you meant something else that could be valid code, you already have a lifetime in scope, all you have to do is apply it, making the suggested fix easy for rustc to provide.
4. This feature is very useful, but its syntax is arcane and not obvious. Users who need this will be likely to ‘flail’ at first, trying to invalidly add lifetime variables to their impl and so on. This could lead them ‘down the garden path’ as the compiler, more and more confused about what they’re trying to express, may make bad suggestions to them about how to annotate their code.
5. It can make the API of libraries doing complex type tricks easier to read. I have a function in a library I’m working on with a constraint `for<'x> T: Trait<Struct<'x, U, Self>>`. This is a very complicated constraint, and reducing it to `T: Trait<Struct<U, Self>>` could help somewhat.

Opinions? 😄

---

<div class="post-metadata">

**Author:** ![jschievink](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jschievink/32/3063_2.png) [@jschievink](https://internals.rust-lang.org/u/jschievink)\
**Post date:** [August 16, 2016, 10:33am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/2 "2016-08-16T10:33:55Z")

</div>

Isn’t the syntax `F: for<'a> Fn<&'a T, Output = U>`?

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [August 16, 2016, 10:42am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/3 "2016-08-16T10:42:42Z")

</div>

Both syntaxes are valid in `where` clauses; `for` before the variable is hypothetically more general (if there were higher kinded variables, you could do e.g. `for<'a> T<'a>: Foo<'a>`), so I think it of it as the ‘canonical’ form and I used it here, but they mean the same thing.

EDIT: the generality is not actually hypothetical, you can write today `where for<'a> &'a T: Trait`.

---

<div class="post-metadata">

**Author:** ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ericson2314/32/246_2.png) [@Ericson2314](https://internals.rust-lang.org/u/Ericson2314)\
**Post date:** [August 18, 2016, 6:05am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/4 "2016-08-18T06:05:02Z")

</div>

Does `where for<'a> T: Trait<'a>` work?

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [August 20, 2016, 9:55pm UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/5 "2016-08-20T21:55:28Z")

</div>

Yes, I think @eddyb explained once that `T: for<'a> Trait<'a>` should be thought of as just sugar for `for<'a> T: Trait<'a>`.

```rust
fn foo<F>(f: F) where for<'a> F: Fn(&'a str) {
    f("hello, world");
}

```

[https://is.gd/wjEpRy](https://is.gd/wjEpRy)

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [August 25, 2016, 11:49pm UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/6 "2016-08-25T23:49:07Z")

</div>

I am of two minds.

On the one hand, I do want to make it less arduous to have to type `'a` all the time, especially for lifetimes only used once. On the other hand, I am wary of "hiding" where lifetimes flow -- this can make for some very confusing errors!

For example, although it is by design (and in fact I insisted on it), I (somewhat) regret that the following works in elision:

```rust
struct Ref<'a, T>;
...
impl Foo {
    fn foo(&self) -> Ref<i32> { ... }
}

```

This is because, when I read that signature, I can't see at a glance that `self` will remain borrowed so long as the return value is in use (in contrast to, e.g., `fn foo(&self) -> &i32`, where I find the result quite obvious).

But also, I am not sure about this:

> [@withoutboats](#):
>
> I think that this is very commonly what you want.

I feel like I've almost _never_ wanted this. If a trait has a lifetime parameter -- which itself is rare -- it's usually tied to some elements in the `Self` type and not something "free-floating", at least in my experience. This can be answered with data, I suppose.

> [@withoutboats](#):
>
> This feature is very useful, but its syntax is arcane and not obvious. Users who need this will be likely to 'flail' at first, trying to invalidly add lifetime variables to their impl and so on. This could lead them 'down the garden path' as the compiler, more and more confused about what they're trying to express, may make bad suggestions to them about how to annotate their code.

This does worry me, of course, as does your point 5. 🙂

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [August 26, 2016, 7:59am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/7 "2016-08-26T07:59:05Z")

</div>

> [@nikomatsakis](#):
>
> For example, although it is by design (and in fact I insisted on it), I (somewhat) regret that the following works in elision:

I can see why - I think to be honest this is more of a weakness of the syntax of lifetime parameters, because you can't see that anything has been elided. I find `fn foo(&self) -> &str`, for example, much less opaque because I can see where the missing lifetime would go. (The fact that it shares the sigil with self also helps).

But this is less likely to be an issue with this ellision, I feel, because it doesn't bind the elided lifetime to any lifetime in particular.

The use case in which I'm seeing this pop a lot is a trait defined like this:

```rust
trait Foo<T: Bar> {
    fn foo(&mut self, &T);
}

trait Bar { ... }

```

My library provides implementations of `Bar`, you provide implementations of `Foo`, which you pass to some function, and then I manipulate your `Foo` with a `Bar`.

Several of my `Bar` implementations have lifetime parameters (some more than one), so I end up with functions like:

```rust
fn baz<T>(foo: T) where T: for<'a, 'b> Foo<BarImpl<'a, 'b>>

```

(The real signatures have even more elements). The reason I explain this is that the trait _itself_ isn't parameterized by a lifetime (I agree that this is very rare), but that its parameterized by a type carrying a lifetime.

Of course what I'd really like here is better impl traits, so I could instead define it as:

```rust
fn baz<T>(foo: T) where T: Foo<impl Bar>

```

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [March 25, 2019, 8:26am UTC](https://internals.rust-lang.org/t/eliding-higher-rank-lifetimes-in-trait-bounds/3861/8 "2019-03-25T08:26:40Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
