Article URL: https://github.com/rust-lang/rust-project-goals/blob/main/src/2026/move-trait.md Comments URL: https://news.ycombinator.com/item?id=49152023 Points: 64 # Comments: 15

We propose to introduce new traits that describe what operations are possible on a type. Today Rust assumes all types can be moved (relocated in memory) and forgotten (via mem::forget). We will introduce traits like Move and Forget that make these capabilities explicit, allowing types to opt out. This follows the precedent set by the Sized hierarchy work, which relaxes the assumption that all types have a compile-time-known size. We will implement MVPs in the compiler, write RFCs, and validate viability through real-world testing in the Linux Kernel. Rust has historically assumed that all values can be moved (relocated in memory) and forgotten (via mem::forget, without running destructors). These assumptions are baked into the language: assignment moves values, and mem::forget is safe. But some types need to opt out of these capabilities: Immobile types: A lot of async futures want to be self-referential, but self-referential types can't be safely moved. The current solution is Pin, which encodes immovability as a property of places rather than types. This leads to significant complexity. As The Safe Pinned Initialization Problem describes, Pin struggles to safely encode self-referential types in systems like the Linux kernel. Guaranteed destructors: Some types need their destructors to run. A Transaction type might require commit() or rollback() before cleanup. A scoped task handle must join before the scope exits. But mem::forget is safe, so Rust can't guarantee destructors run. This blocks patterns like safe scoped spawn for async, where the spawned task borrows from the parent scope. We propose to generalize Rust's type system with new auto-traits that describe what operations are possible on a type. The framing is positive: traits represent capabilities. At the base layer, types may have no special capabilities. We then layer on the things we need: This follows the precedent set by the Sized hierarchy work. Just as that work relaxes "all types have compile-time-known size" to support scalable vectors, this work relaxes "all types can be moved" and "all types can be forgotten." Types implementing !Move cannot be moved and must keep a stable address for their entire existence. This is simpler than Pin because immovability is a type property, not a place property. Construction of !Move types will rely on work from #t-lang/in-place-init. With !Forget, we could build safe scoped spawn: the handle's destructor joins the task, and because the handle can't be forgotten, the join is guaranteed. This unblocks patterns that are currently impossible in safe Rust.