Email or username:

Password:

Forgot your password?
Mara

🦀 New #rustlang blog post! Learn about temporary lifetimes, about something called "temporary lifetime extension", and my idea for a new language feature called "super let".

blog.m-ou.se/super-let/

22 comments
Jonathan Müller

@Mara I have a lot of headache with those currently at work - but in C++, where I don't have the borrow checker to detect dangling reference.

So I'm currently introducing a temporary<T&&, Lifetime> type to implement the borrow checker in the library...

Tavian Barnes

@Mara How horrible would it be to infer this rather than require it to be written out?

Mara

@tavianator To silently extend the lifetime of a `let` whenever necessary? I think that would result in the compiler silently accepting lots of code that shouldn't compile, hiding bugs and causing subtle unintended behavior. I don't think that's a good idea. ^^'

nyctef

@Mara @tavianator One worry I have (as a novice rust programmer who relies heavily on the very helpful error messages) is that if the compiler tells me "help: try using super let" then I'm probably going to press the "make my code compile" button without understanding the edge cases or consequences involved. So it may still cause some of these issues in practice?

(thanks for the blog post - it was a really interesting read! :)

Mara

@nyctef @tavianator I do think just adding "super" when the compiler suggests it works out fine in basically all cases! I just want it to be visible to a reader of the code, that something is going on with the lifetime of that object. Otherwise, it's very easy to hide a surprise in the code.

RealGene ☣️

@Mara
I nominate "make" as the keyword for "super let". 'let' is passive, 'make' is active.
The intention to the compiler is clearer, and it certainly reads/scans better.

Using 'super' implies it is a modifier for what follows (à la const in C), which means it would/should be applicable in other circumstances, which would complicate parsing for just the single use case of 'let'…

waffle

@RealGene @Mara I don't see how super let would complicate parsing. Rust parser has to do some weird things, but this is not one of them.

The problem with make is that it's not a reserved keyword, so we'd need to introduce a new keyword in an edition, use ugly k# in previous ones and also disallow people from using it for names. A lot of noticeable disadvantages.

Besides IMO it's nice that super is reading as a modifier, it should help teaching "this is like let but with a small twist..."

RealGene ☣️

@wffl @Mara
IANAL but: super is already in use as a keyword/adjective to identify a module parent.

So now the parser must distinguish between 'super let' and 'super::let'.

The behavior described for super let doesn't yet exist anyway, so a new release would be required regardless.

So add 'make' as a super let, or 'durable' or 'perpetual' as a let modifier when you add the functionality…

You want a modifier to at least hint at what it's going to do. Super is kind of vague.

@wffl @Mara
IANAL but: super is already in use as a keyword/adjective to identify a module parent.

So now the parser must distinguish between 'super let' and 'super::let'.

The behavior described for super let doesn't yet exist anyway, so a new release would be required regardless.

So add 'make' as a super let, or 'durable' or 'perpetual' as a let modifier when you add the functionality…

Mara

@RealGene The compiler can look at two words instead of just one, so that's no problem. ^^

`super let` is currently always an error, so nothing breaks if we give it meaning. So we can do that without needing a new edition.

`make` is currently not a keyword and can be used as a regular identifier (e.g. variable or function name), so making that a keyword would break things and thus require an edition.

Lore :v_enby:

@Mara I like this idea, helps with what feels like gymnastics in several situations. Especially helps as a learning opportunity on temporary lifetime extension to help demystify rust. A natural extension would be for function bodies to use "super let", so that `pin!` could be a [safe] function. I hit this problem much more often than the nested blocks in your exposition. Though that sounds like an advanced form of "placement" so there might be a lot wrapped into there. But it would be good to consider how this feature may evolve longer term such as for those use cases. Syntactically I think the use of "super" here is clever in a good way — an alternative syntax might involve explicit lifetimes but any options that come to my mind there feel needlessly verbose.

@Mara I like this idea, helps with what feels like gymnastics in several situations. Especially helps as a learning opportunity on temporary lifetime extension to help demystify rust. A natural extension would be for function bodies to use "super let", so that `pin!` could be a [safe] function. I hit this problem much more often than the nested blocks in your exposition. Though that sounds like an advanced form of "placement" so there might be a lot wrapped into there. But it would be good to consider...

Mara

@lorepozo Yes! Allowing `super let` at function level for functions that basically place additional values in the caller's stack frame would be useful! Then a function could create an object (in the caller's frame) and return something that references it, like a safe pin() would need to.

That would need to be part of the function _signature_ though. I don't think we should (or can) allow any regular fn to start placing extra objects into the parent's scope.

Mara

@lorepozo I've added a small aside about this to the blog post.

llogiq

@Mara if we really implement that, I pledge to instate a clippy lint to deny super let on any Mutex type. We definitely don't need mental gymnastics around those.

Gustav Wengel

@Mara Super neat introduction to temporary lifetime extensions, which I think is one of those things that for the most part slide into the background and you don't _need_ to think about. Unsure about super let though, can definitely see the appeal, but not sure the upside is worth the extra complexity in the language.

Drew 🐘

@Mara I like the idea a lot. I ran into these quite a bit while learning rust. Thanks to this blog post I have a better appreciation for why it was so confusing at the time. Now that I know the rules I doubt I would opt into super-let very often but the ability of the compiler to suggest using this would build some educational content for how the borrow checker sees things into the tooling, which I'm almost always in favor of.

Overloading `super` feels needless to me though. `ext(ended) let`?

Mara

@dvogel I just picked `super` 🦸‍♀️ because it's already a keyword today. If we do it over an edition, we could pick any word. :)

Tristam

@Mara I find it kind of weird that the extended lifetime annotation (i.e. `super`) ends up on the let binding, and not on the temporary whose lifetime will be extended

Mara

@swiftcoder Huh? The let binding is for the value that will be lifetime-extended. (It's no longer a "temporary" because it now has a name.)

Tristam

@Mara in that case seems I misunderstood. Super let only extends its own lifetime, not the lifetime of any temporaries nested within expressions?

Mara

@swiftcoder Ah. Well, both?

`super let a = Thing;` makes `a` live as long as the surrounding block. The lifetime that allows the block's final expression to be `&a`, basically.

On top of that, we still have temporary lifetime extension, just like we have in a regular `let`:

`let a = &temp();` makes the temporary life as long as `a`.

Same for `super let a = &temp();`: the temporary will live as long as `a` (which might live longer than it would have in a regular `let`).

Gankra

@Mara hey listen we already have a heavily abused contextful keyword

"for let" 2024

Go Up