# Lt\<'a\> lang item (because we don't have DerefMove) - lifetimes for fn!

**URL:** <https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169>\
**Category:** Unsafe Code Guidelines\
**Created:** [August 11, 2021, 9:40pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169 "2021-08-11T21:40:10Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [August 17, 2021, 6:56pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/21 "2021-08-17T18:56:26Z")

</div>

> [@Soni](#):
>
> `fn foo() -> Lt<'a, u32>;`

Where does `'a` come from? How is anyone going to write this code? How am I, as a reader of the code, going to figure out what `'a` is?

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [August 17, 2021, 8:24pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/22 "2021-08-17T20:24:16Z")

</div>

As a possibly inaccurate data point only, I recall reading a few years ago that the devs of musl libc had given up on trying to fix all the corner cases of library unloading, and had made `dlclose` do nothing.

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [August 17, 2021, 8:54pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/23 "2021-08-17T20:54:10Z")

</div>

That [would appear to be true](https://git.musl-libc.org/cgit/musl/tree/src/ldso/dlclose.c) since it just checks whether the handle is valid or not.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 17, 2021, 10:11pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/24 "2021-08-17T22:11:48Z")

</div>

Usually from the `&'a Library` you `get::<Handle>` from. You don't write it, the libloading/other dynamic (un)loading library generates these bindings for you.

third-party lib.rs:

```rust
fn foo() -> bool {
  false
}

```

your lib.rs/main.rs:

```rust
let library = Library::open::<GeneratedLibSpec>("path/to/lib.so");
let foo: fn() -> Lt<'_, bool> = library.get::<GeneratedLibSpec::foo>();
assert_eq!(false, foo().0);

```

Making a library loader that assumes everything is safe is inherently unsound. Making a library loader that generates safe bindings is something else entirely. This can be done today, you do not need a lang item to do this, but unfortunately ppl won't do this, because ppl don't care.

(Now if only there was a way to force-kill threads on unloading...)

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [August 17, 2021, 11:32pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/25 "2021-08-17T23:32:57Z")

</div>

> [@Soni](#):
>
> ```rust
> let foo: fn() -> Lt<'_, bool> = library.get::<GeneratedLibSpec::foo>();
> 
> ```

This makes no sense though. The lifetime is on the returned `fn` as a whole, not its return value. Any lifetimes in the signature need clamped to the `Library` instance lifetime. This is where the library's assumptions of what `'static` means is upended and Rust's guarantees start breaking down. Arbitrarily adding it to just the return value is of no value IMO.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 18, 2021, 12:06am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/26 "2021-08-18T00:06:21Z")

</div>

Function return values are covariant. That is the correct variance for a shared reference. See here: [Subtyping and Variance - The Rustonomicon](https://doc.rust-lang.org/nomicon/subtyping.html#variance)

Even tho there's no way to tag a function reference directly with `'lt`, you can just use an `Lt<'lt>` return value to do it anyway and get the correct semantics.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [August 18, 2021, 2:39am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/27 "2021-08-18T02:39:21Z")

</div>

Question; why not just return `Lt<'a, fn() -> T>` instead of `fn() -> Lt<'a, T>`?

Then, you don't have to (or want to) have a magic `Lt<'_, _>` which coerces to its wrapped value; you just want `Lt<'_ impl Fn>` to `impl Fn`.

This can be trivially done on nightly today. Unfortunately, it can't be done without use of the mechanism by which the `Fn` trait(s) pack their argument types, so it can't be done stably (without janky airity hacks) without stable `Fn` traits without sugar.

It's cool that returning `Lt` can be abused to get a similar effect to adding a lifetime into `fn` (rather than the current `&'static`esque semantics) on stable Rust, but you're asking for a language addition to make `Lt` work "better" for this purpose and irlo is about the design and implementation of the Rust language, not using current stable Rust (that's for urlo).

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 18, 2021, 10:44am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/28 "2021-08-18T10:44:48Z")

</div>

> [@CAD97](#):
>
> It's cool that returning `Lt` can be abused to get a similar effect to adding a lifetime into `fn` (rather than the current `&'static` esque semantics) on stable Rust, but you're asking for a language addition to make `Lt` work "better" for this purpose and irlo is about the design and implementation of the Rust language, not using current stable Rust (that's for urlo).

It's kinda both. USG is a thing here for a reason, as this thread is filed under USG. The lang item is purely optional for convenience as an added bonus and not a requirement.

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [August 18, 2021, 6:00pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/29 "2021-08-18T18:00:59Z")

</div>

It's wrong to suggest that, in principle, any function returning `Lt<'a>` _must only_ live for `'a`. Firstly, don't forget that `fn` is pretty much a reference type which has implicit `'static` lifetime. Restricting its lifetime to the return type only 'works' due to an (unfortunate) detail that propagates it to the function pointer itself even though it doesn't contain any value of that type, and this is arguable wrong. What's maybe more fatal to this approach is that there is ample reason to _relax_ this later. More in detail, consider:

```rust
fn leak<'a>(Box<U>) -> &'a mut U

```

This function, using the generic type `for<'a> fn(Box<U) -> &'a U` is `'static`. Indeed:

```rust
fn leak<'a>(b: Box<u32>) -> &'a mut u32 {
    Box::leak(b)
}

fn assert_static<F: 'static>(_: F) {}

fn main() {
    assert_static(leak);
}

```

But for implementation defined reasons the strictly more specific instantiation/subtype with a non-generic lifetime is not `'static`. That's.. odd to say the least and should get fixed. No, the lifetime of the result type has nothing at all to do with the lifetime of the function pointer. Consider that a function that unconditionally panics could in principle be allowed to 'return' any type—including any type that has a smaller lifetime than itself.

Also note that the use and safety of this type relies on negative reasoning: The lifetime or a function with that return type is no larger than `'a`. However, as outlined above, there is reason why the lifetime of some fn-pointers could be _relaxed_. The imo more appropriate way if we're making a language change anyways—which a lang item is—would be to embrace the idea of `fn` being a special case of `&` and adding a lifetime argument to it.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 18, 2021, 6:27pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/30 "2021-08-18T18:27:44Z")

</div>

This feature has existed since Rust 1.0, so it's safe for unsafe code to rely on it. Deprecating it now would be devastating.

Adding a lang item isn't a breaking change. Not adding a lang item isn't a breaking change either. Adding a lifetime argument to fn is (and is unnecessary given that we already have what we need today).

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [August 19, 2021, 12:02am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/31 "2021-08-19T00:02:46Z")

</div>

> [@197g](#):
>
> But for implementation defined reasons the strictly more specific instantiation/subtype with a non-generic lifetime is not `'static` . That's.. odd to say the least and should get fixed. No, the lifetime of the result type has nothing at all to do with the lifetime of the function pointer.

[It's from RFC 1214](https://rust-lang.github.io/rfcs/1214-projections-lifetimes-and-wf.html) (not just an implementation detail). A desire to make an exception for function pointers [has come up before](https://github.com/rust-lang/rust/issues/80317) ([IRLO thread](https://internals.rust-lang.org/t/pre-rfc-relax-fn-pointer-lifetimes/13703)). As far as I know an actual RFC has yet to surface though.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 19, 2021, 12:28am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/32 "2021-08-19T00:28:51Z")

</div>

Please stop trying to mess with the lifetime of `fn`. Instead, exploit it! `fn` has a lifetime and you can set it to whatever you want it to be, so go ahead and make unsafe code that relies on it for correctness!

You wanna make a safe JIT with Drop? Make a safe JIT with Drop! Make a `&'a FuncHandle` that ~~derefs~~ `get()`s to an `fn() -> Lt<'a>`! This is sound today, and you can rely on it! If the lang team wants to make it unsound in the future, they should make a Rust 2.0 instead!

Don't let your dreams be dreams. `fn` has a lifetime. So does you. Make the best of it! :‌)

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [August 19, 2021, 1:59am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/33 "2021-08-19T01:59:42Z")

</div>

> [@197g](#):
>
> This function, using the generic type `for<'a> fn(Box<U) -> &'a U` is `'static` . Indeed:

`for<'a> fn(Box<U>)->&'a U` is `'static` because it has an HRTB lifetime, thus the `&U` can be created at any time the function can be statically called. However, given an externally defined `'a`, `fn(Box<U>)->&'a U` has a bounding lifetime of `'a`, because calling the fn-ptr outside of that lifetime would be unsound (it could produce a `&'a` that is dangling or aliased).

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [August 19, 2021, 3:41am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/34 "2021-08-19T03:41:40Z")

</div>

[Any function pointer output lifetime must also be an input lifetime.](https://doc.rust-lang.org/stable/error-index.html#E0581) (You can't have a `for<'a> fn(Box<U>)->&'a U`.)

---

<div class="post-metadata">

**Author:** ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)\
**Post date:** [August 19, 2021, 10:26am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/35 "2021-08-19T10:26:23Z")

</div>

That looks like a restriction on HRTB lifetimes, rather than external lifetimes. Side note, that means you can't convert Box::leak into an fn-ptr without a fixed lifetime.

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [August 19, 2021, 11:26am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/36 "2021-08-19T11:26:49Z")

</div>

That is a wrong interpretation of soundness and stability. Unsafe code that relies on the _absence_ of a (trait) bound that is outside its control has _always_ been unsound with regards to forward compatibility. Expanding the lifetime of a pointer is a relaxation and relaxations are non-breaking. (For example, this is why `Pin` can _only_ be implemented by std because it relies on non-relaxation of `DerefMut` for references which is a `core` trait and governed by those rules). Unless you can point out an RFC that makes it a breaking change to relax this lifetime I'm afraid that also applies to that example. There has been one specifically to forbid any `&` from implementing `DerefMut`. (Although, it might have been without RFC? I'm not sure, but the lang-team signed off on it I'm decently sure).

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [August 19, 2021, 11:46am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/37 "2021-08-19T11:46:51Z")

</div>

Huh, I stand corrected to know it has an RFC describing the rules. However, it specifies details for the implication to _determine_ `Type: 'a`. And it does it by _adding_ a new rule

> This last rule, however, is not only new, it is the crucial insight of this RFC.

Nowhere in this RFC does it state or imply that it adds rules for _negative_ reasoning, i.e. for `Type: !'a`. But that's what the goal of `Lt` is, to have a type where it implies that `fn() -> Lt<'a>` lives _no longer_ than `'a`. (That is, the compiler and soon Polonius implements a monotonic and constructive logic relating types and bounds). It also doesn't really relate to function items but rather to well-formed type/trait declarations. It doesn't modify the rules for fn liftime impliciations but the implicit context available for checking well-formedness of declarations.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [August 19, 2021, 11:59am UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/38 "2021-08-19T11:59:25Z")

</div>

fn() -\> Lt\<'a\> can live longer than 'a: it's covariant.

it just also happens to borrow something. if that something only lives as long as the current context, then fn() -\> Lt\<'a\> can't live longer than the current context.

not negative reasoning, unless you wanna argue `&'a Foo` is a negative reasoning.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [August 19, 2021, 11:10pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/39 "2021-08-19T23:10:10Z")

</div>

It's ultimately a restriction to make sure the associated type in the implementation of the `Fn` traits are well-defined, basically. (The same restrictions apply to `dyn Fn` and friends, more directly.)

Regarding `Box::leak` -- yes, exactly, [the unconstrained lifetime is now early-bound](https://github.com/rust-lang/rust/issues/33685) (see the **more details** section).

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [August 19, 2021, 11:20pm UTC](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169/40 "2021-08-19T23:20:35Z")

</div>

You are suggesting that rust might make `fn()` bivariant in its return type, the weakest type of variance possible. This would be a dramatic departure from well-established type theory that [functions should be contravariant in their arguments and covariant in their return type](https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance).

I cannot even think of a language with subtyping and generics which does not work this way. (aside from, ironically, silly bits of rust involving the Fn trait, where args and return type are both invariant due to the trait system. Notice this is a _stronger_ restriction, not a weaker one!)

> Consider that a function that unconditionally panics could in principle be allowed to 'return' any type—including any type that has a smaller lifetime than itself.

What does it matter that a function `fn() -> &'a T` _could_ be one that always panics? If the compiler sees a variable of type `fn() -> &'a T`, it has to conservatively assume that it _might not_ be one that always panics.

> Also note that the use and safety of this type relies on negative reasoning: The lifetime or a function with that return type is no larger than `'a` .

All reasoning about lifetimes is negative reasoning. The sole purpose of lifetimes is to _prevent_ the compilation of code in order to allow other code to be correct.

> The imo more appropriate way if we're making a language change anyways—which a lang item is—would be to embrace the idea of `fn` being a special case of `&` and adding a lifetime argument to it.

I do not disagree here. Having a lifetime argument that expressly belongs to the `fn` would be better than any hack that slips it into the return type.

[Previous page](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169.md?page=1)

[Next page](https://internals.rust-lang.org/t/lt-a-lang-item-because-we-dont-have-derefmove-lifetimes-for-fn/15169.md?page=3)
