Pin
Rust’s `Pin` type and the broader async model are criticized as powerful but conceptually hard to grasp, largely because pinning only matters for a narrow class of non-`Unpin` types such as self-referential futures. Commenters debate whether this complexity is an inevitable consequence of Rust’s existing `&mut` semantics and zero-cost abstractions, or a design misstep that could have been avoided with different primitives like move constructors or better thread models. Many agree that tooling, documentation, and higher‑level abstractions make day‑to‑day use bearable, but several engineers still find async Rust significantly more demanding than async in languages like Go or JavaScript.
Scope of Pin and &mut in Rust
- Several commenters note that
&mutis “too powerful”: it allows moving viamem::swap,mem::replace,Option::take, etc. - Some argue that if moving through
&mutwere restricted (or those functions wereunsafe), self‑referential values could be safe withoutPin. - Others counter this would be a non‑starter: it would break large amounts of existing code and there are many move‑via‑reference patterns in the wild.
Move semantics, !Move, and alternative designs
- Proposed alternative: a language‑level
Movetrait (analogous toCopy) or split traits for trivial vs custom moves, enabling self‑referential types and richer movement semantics. - Some see this as a cleaner long‑term design that could avoid
Pin; others argue move constructors would be even more complex for users thanPin. - There is interest in “languages after Rust” that keep Rust’s safety but redesign moves, async, and comptime.
Async Rust, Pin, and ergonomics
- Many see
Pinas tightly tied to async/await and futures; some feel Rust’s async story is “half‑baked” and comparatively painful versus other languages. - Others insist that with macros (
pin!, pin‑project) and idioms,Pinisn’t that hard in everyday async code. - A common pattern is “I add
Pinwhere the compiler complains until it compiles,” reflecting weak intuition about when it’s needed.
Why Pin feels confusing
Pinalone doesn’t define what is allowed; its meaning depends on whether the inner type isUnpinand on custom APIs built around it.- Documentation is criticized as technically accurate but opaque, especially for
Unpinand its double‑negative feel. - Users struggle with action‑at‑a‑distance: changes far from the error site can suddenly introduce
Unpinconstraints. - Suggestions include more practical, “systems‑engineering” docs and better teaching analogies (Velcro/smooth, magnets/non‑magnetic, stapling vs hooks).
Unpin and typestate
- Clarified view:
Pinis a state of a pointer, not a property of the data.- For most types (those that are
Unpin),Pin<T>is effectively a no‑op. - Only types that rely on their address (e.g., self‑referential, some futures) truly care about pinning.
- Pinning vs non‑transitive pinning of fields (via projection) is acknowledged as necessary but confusing accidental complexity.
Use cases beyond async
- Reported non‑async uses:
- FFI where a C API gives a raw pointer that must not move.
- OS or system types (e.g., mutex/futex implementations) whose docs require stable addresses across their lifetime.
Async vs threads and broader concurrency debate
- One camp argues all async is a workaround for inefficient OS threads; “fix threads” and much complexity (including
Pin) disappears. - Others respond that:
- OS‑level fixes are unrealistic or outside language designers’ control.
- Async offers benefits such as cancellation, fine‑grained control, and embedded/no‑alloc scenarios.
- Thread APIs and context‑switch costs still limit simple “just use threads” answers.
- Go’s model is cited both positively (no explicit async) and negatively (composability, context management, hidden overhead).
HN‑specific meta: titles and moderation
- Many dislike the bare title “Pin” as uninformative or clickbaity; some want language tags like “[Rust] Pin”.
- Others note HN guidelines favor original titles but are applied with varying strictness; debate centers on balancing fidelity vs clarity.