Animats
Good to see this.

"There is another theme running through here: moving the borrow checker analysis out from the compiler’s mind and into types that can be expressed. Right now, all types always represent fully initialized, unborrowed values. There is no way to express a type that captures the state of being in the midst of iterating over something or having moved one or two fields but not all of them. These changes address that gap."

I have some misgivings about trying to do everything with types. That leads to having to perform complex, hard to understand operations on types, as you add and remove restrictions. Keeping borrowing orthogonal from types may be clearer. Not sure about this, though.

I'd like to see back references addressed, so structs can have references to their owners. General concept: when possible, do statically what Rc, Weak, and .borrow() can do for backlinks at run time. Such static analysis seems possible for non-mutable references. Mutable is going to be tough, though. It's a lot like compile-time single-lock deadlock detection, where you try to check that the same lock is never locked twice in nested contexts.

tmpfs
These are some really good suggestions.

I think a "syntax for lifetimes on places" (2) is really neat and would make lifetimes much easier to reason about, by removing the indirection and being explicit about where the borrow is from in the declaration makes the intention much clearer.

But my personal favorite is the point about "internal references" as I struggled with this a couple of times. I think this would be an excellent improvement. In the end I used ouroborous [1] to achieve this but having it built in to the language would be excellent.

[1] https://docs.rs/ouroboros/latest/ouroboros/

superb_dev
I wanted to share a technique I saw recently related to a post linked within this post: https://smallcultfollowing.com/babysteps/blog/2015/04/06/mod...

> The primary disadvantage comes about if you try to remove things from the graph. The problem then is that you must make a choice: either you reuse the node/edge indices, perhaps by keeping a free list, or else you leave a placeholder.

There’s another option, called generational indices! I discovered this from the “generational_arena” crate: https://docs.rs/generational-arena/latest/generational_arena...

yuvadam
I really enjoyed this post, resonates with many small experiences I had learning the various patterns that do and don't work in Rust.

Also blows my mind how crazy complex these language design topics are.

aabhay
It would be cool to annotate the lifetime using this syntax instead:

-> &map’s mut V

The apostrophe here matches the syntax of lifetimes roughly and to me makes it EXTREMELY clear whats going on.

yencabulator
Leave it to emojis to ruin communication:

    // A thread to consume those values:
    std:<emoji here censored by hn>:spawn(move || {
IshKebab
These would be very welcome changes.

How do self references work when the struct is moved, given that they're pointers?

Also I'm not sure about having a feature that only works for private functions. I can imagine that would be very weird and annoying. I think it would be fine if it were allowed for public functions too, we just need better built in tooling to warn you about API breaking changes. After all you can already break API compatibility in obvious and very subtle ways. It would be great if Rust said something like "this is an API incompatible change; you need to increase the version number".

I think there are third party tools that try to do that but it would be great if it was first party.

pjmlp
While I welcome the effort going into improving the lifetimes experience in Rust, this also kind of reflects that the approach being taken by other languages, meaning keeping automatic memory management by default, and only enough affine/linear typing support for when performace really, really matters, is a more productive approach.

Examples of that approach, D, Swift, Chapel, Linear Haskell, OCaml Effects.

The changes on the article, while welcomed in the context of Rust typesystem, will make being aware of all borrow check rules even more complex, and back into language lawyers kind of C++ developer experience, unless backed up by IDE tooling, on when to write what suggestions.

cassepipe
I am not well versed in Rust so I can't judge the design decisions fairly but I do find that cpp2's in, out, inout, move and forward keywords for functions arguments much easier to follow mentally that rust's lifetime annotations : https://youtu.be/6lurOCdaj0Y?feature=shared&t=3076

We can do the same kind of (basic?) borrow checking with those can't we ?

conaclos
View types make me think of the modifies clause introduced by some verification tools and in an earlier specification of Eiffel [1]. Basically the clause allows you to list the fields that are affected by a function with mutations.

[1] https://bertrandmeyer.com/2011/07/04/if-im-not-pure-at-least...