HN Debrief

Rust project goals: Immobile types and guaranteed destructors

  • Programming
  • Open Source
  • Developer Tools
  • Infrastructure

The post is a Rust project goal document, not an approved language change. It sketches a path toward making “can this value ever move?” a property of the type with `!Move`, instead of expressing immobility indirectly through `Pin`, and pairs that with work on stronger destructor guarantees such as `!Forget` and possible must-destroy or linear patterns. The pitch is that Rust’s current model makes several useful patterns either impossible in safe code or wrapped in confusing escape hatches, especially self-referential types, scoped async tasks, and APIs where cleanup must happen exactly once.

If you build serious Rust infrastructure, watch this closely before cementing new `Pin`-heavy APIs. The likely direction is more explicit type-level constraints around movement, leaking, and destruction, which could reshape async runtimes, FFI with C++, and any library that currently relies on tricky drop behavior.

Discussion mood

Mostly excited and optimistic. People see this as a serious attempt to fix one of Rust’s ugliest corners, especially around `Pin`, async cancellation, and self-referential types. The caution comes from how invasive the change would be and how many backcompat traps sit in standard traits, collections, and existing `Pin`-based APIs.

Key insights

  1. 01

    Scoped async is the killer use case

    The proposal lands hardest in async. Rust already has scoped threads, where child work must finish before the parent returns, so borrowing stack data into concurrent work is safe and ergonomic. Async tasks do not have that guarantee because futures are plain values that can be cancelled before completion. Stronger destruction guarantees would let async code recover that structured-concurrency model without falling back to heap allocation or garbage collection tricks. That is why several people framed this less as a niche type-system cleanup and more as a missing foundation for Rust async.

    If you maintain async infrastructure, expect the biggest product impact here rather than in low-level type wizardry. Designs that currently force `'static`, cloning, or awkward task ownership may get a much better long-term model.

      Attribution:
    • simonask #1 #2
    • pornel #1
  2. 02

    Pin and !Move solve different problems

    The useful distinction is that `Pin` constrains a value after it has been placed somewhere, while `!Move` would describe a type that cannot ever be moved once constructed. That is why `Pin` still matters for objects that are movable during setup and only need a fixed address later. It is also why so many explanations of `Pin` end up tangled. The current abstraction tries to encode lifecycle and location through wrappers and marker traits, and even experienced Rust users mix up `Pin`, `Unpin`, and true immobility. `!Move` is attractive because it removes a whole layer of indirection for the cases where the object itself is inherently stationary.

    Do not assume this is a drop-in rename of `Pin`. Review any API that relies on “movable until activation” semantics, because those may still need a separate mechanism even if `!Move` ships.

      Attribution:
    • Georgelemental #1
    • mcherm #1
    • Dagonfly #1
    • stymaar #1
  3. 03

    Linear types would clean up transactional APIs

    The discussion around `!Destruct` or must-move types showed a concrete API win. Today a transaction object usually has to choose between silent rollback on `Drop`, panic in `Drop`, or callback-style control flow, all of which are awkward. With a linear type, the compiler could force every control path to explicitly consume the transaction through `commit` or `rollback`. The important detail is that you do not get to discard such a value in arbitrary code. Disposal would require destructuring or another explicit consuming operation defined where the private fields are visible.

    If your library has resources that must be finalized exactly once, keep an eye on this branch of the work. It could replace ad hoc runtime checks with compile-time enforcement and simplify API shape.

      Attribution:
    • yccs27 #1
    • vlovich123 #1
    • simonask #1
  4. 04

    Associated types are the real compatibility trap

    The sharpest technical concern was not about syntax but about generic contracts buried in the standard library. Traits like `Iterator` and `Deref` have associated types that existing code implicitly treats as movable. If those become `?Move`, vast amounts of generic code lose assumptions they rely on today. If they stay `Move`, whole classes of immobile values remain second-class citizens. That is why people pointed to newer work on implicit auto traits and only-bounds as the actual enabling machinery. Without that, `!Move`, `!Forget`, and related features stay boxed in by backcompat.

    For teams with heavy generic libraries, the migration story will matter more than the headline feature. Watch the trait-system work, not just the surface proposal, before betting on when this becomes usable.

      Attribution:
    • Dagonfly #1 #2
    • ameliaquining #1
    • yoshuaw #1
  5. 05

    Guaranteed destruction is narrower than no leaks

    The most useful clarification was that `!Forget` is not trying to make logical leaks impossible. Reference cycles and nonterminating threads mean that goal is undecidable in general. The intended contract is tighter and more practical. If ownership really leaves scope and the underlying storage is reused, the destructor must have run first. That is enough for resource cleanup patterns that need certainty at scope boundaries, and it avoids claiming the language can ban every leak trick.

    Read destructor guarantees as a scoped safety contract, not a universal leak prohibition. That makes it much easier to judge where the feature would actually help your code and where it would not.

      Attribution:
    • klauserc #1
    • Dagonfly #1
    • afdbcreid #1

Against the grain

  1. 01

    This could still lose to pin ergonomics

    The proposal has momentum, but it is not a done deal. Commenters noted that it directly conflicts with the accepted project goal around pin ergonomics, and the language team may decide that improving `Pin` is safer than redesigning movement semantics across the type system. The strongest reason to doubt this path is not lack of demand. It is that the semantic and compatibility fallout may simply prove too hard to resolve cleanly.

    Do not roadmap against this as if it were settled. If you need a production answer in the near term, assume `Pin` remains the supported path for a while.

      Attribution:
    • ameliaquining #1
    • afdbcreid #1
  2. 02

    This is not Rust becoming C++

    A few comments pushed back on framing this as Rust adopting C++ object semantics. The proposal is still about adding narrower opt-in constraints, not implicit user-defined move constructors or C++-style default behavior. The C++ connection is mostly practical. Rust needs a better model for interop and for expressing patterns C++ code already depends on, but the intended Rust design remains explicit and restrictive rather than making everything implicitly movable in the C++ sense.

    If you explain this internally, present it as targeted new guarantees, not as convergence with C++ language philosophy. That will lead to better API decisions and fewer false expectations.

      Attribution:
    • afdbcreid #1
    • kibwen #1
    • panstromek #1

In plain english

`!Destruct`
A proposed Rust property for values that cannot simply be dropped and must instead be consumed in an explicit way, similar to linear types.
`!Forget`
A proposed Rust property that would require destruction to happen before a value’s storage is reused, instead of allowing the value to be silently leaked.
`!Move`
A proposed Rust type property meaning a value cannot be moved to a different memory location after it is created.
`Deref`
A Rust trait that controls how pointer-like types behave when you access the value they point to.
`Pin`
A Rust type wrapper used today to promise that a value will stay at a fixed memory location after it has been pinned.
`Unpin`
A Rust marker trait for types that are safe to move even when wrapped in `Pin`.
scoped spawn
Starting a task or thread whose lifetime is tied to the current scope so it can safely borrow local data.
structured concurrency
A concurrency model where spawned work is guaranteed to finish before the scope that created it exits.

Reference links

Rust design proposals and project docs

Rust async and destructor semantics

Related language models and interop references