Rust project goals: Immobile types and guaranteed destructors

Rust maintainers are exploring new type-level traits like `!Move` and `!Forget` to support immovable types and guaranteed destructors, aiming to fix long-standing issues around async, self-referential structures, and memory leaks. Commenters highlight how this could enable safer structured concurrency (e.g., scoped async tasks with guaranteed cleanup) and more expressive APIs such as linear “must-use” resources, while also noting serious backward-compatibility challenges with existing traits, collections, and the `Pin` model. There is broad enthusiasm for the capabilities these features could unlock, tempered by recognition that the design is complex, not yet finalized, and may force trade-offs with alternative proposals like “pin ergonomics.”

High-level idea

  • Proposal introduces traits like !Move, !Forget, and eventually !Destruct to:
    • Make immovability a property of the type instead of the place (replacing much of Pin).
    • Guarantee that destructors will run (or that leaking is impossible) for certain types.
    • Lay groundwork for linear / must-move types.

Async Rust & structured concurrency

  • Major motivation is better async/structured concurrency:
    • Today, async tasks can be cancelled arbitrarily, so destructors may never run.
    • This blocks fully safe “scoped tasks” analogous to scoped threads.
    • With !Forget, task handles could be guaranteed to be dropped, making scoped async safe and ergonomic.
  • Also helps:
    • Recursive async functions (no hacks with Box::pin).
    • Async functions borrowing from outer scopes instead of cloning.

Immovable types vs Pin

  • Pin is widely seen as confusing and a “hack”:
    • It pins places and has tricky Unpin semantics and projection rules.
    • Low-level async code using Pin is unergonomic and relies on unsafe.
  • !Move would make immobility intrinsic to the type:
    • Enables safe self-references and complex patterns that Pin cannot fully support.
  • There is an alternative “pinned places”/pin ergonomics path; this proposal is explicitly an alternative and aims to deprecate Pin long-term.

Leak control and !Forget

  • !Forget aims to ensure a destructor runs before storage is reused.
  • Leaks via mem::forget or ref cycles:
    • Proposed to be constrained by requiring T: Forget for Rc/Arc and similar types.
    • Infinite loops or sending values to other threads are not considered “forgetting,” as the scope never ends.

Linear / must-move types (!Destruct)

  • Would force explicit destruction paths:
    • APIs like transactions could statically require exactly one of commit/rollback.
    • “Silent rollback” or panic-in-Drop patterns could be avoided.
  • Destruction would typically require destructuring or dedicated consuming functions in the defining module.

Backwards compatibility and std impacts

  • Backcompat is a major risk:
    • Existing generics implicitly assume everything is movable and droppable.
    • Traits like Iterator::Item and Deref::Target become problematic when some types are !Move.
    • Collections like Vec<T> inherently move elements; likely they cannot support !Move types, or only via restricted APIs.
  • Editions help but cannot solve everything; careful design of defaults and bounds (T: Move vs T: ?Move) is crucial and nontrivial.

Relation to algebraic effects and C++

  • Some see these traits as effect-like: drop<T>, move<T>, forget<T> behave like implicit effects attached to functions.
  • Others argue it’s mainly about type properties and potential future effect systems.
  • Comparisons to C++:
    • Rust is not adding implicit move/copy constructors.
    • Immovability and guaranteed destructors make interop with C++ and certain patterns (self-references, complex object graphs) easier, but with stricter, explicit semantics.

Status and uncertainty

  • This is a project goal, not an accepted language change.
  • It competes with the pin-ergonomics goal; many expect immovable types to win if only one survives, but:
    • The change is pervasive and complex.
    • Semantics, backcompat, and std integration remain open and could still derail or significantly reshape the design.