概要
Rustの型システムに Move や Forget などの新しいトレイトを導入し、型ごとに移動や忘却の可否を明示化 自己参照型 や 確実なデストラクタ実行 など、現状のPinでは困難なパターンに対応 Linuxカーネルなど実例で検証しつつ、 安全なscoped spawn や async drop の実現を目指す Pinの複雑さを解消し、 型プロパティ として不変性や忘却不可を管理 既存のFutureトレイトの変更は今回のスコープ外
Rust型システムの進化:Immobile typesとGuaranteed destructors
- Rustは 全ての型が移動可能かつmem::forgetで忘却可能 という前提
- 一部の型(自己参照型や必ずデストラクタを走らせたい型)はこの前提から外れたい要件
- Pin は「場所」の不変性を保証するが、 型 として不変性を持たせる方がシンプル
- Moveトレイト で「この型は移動可能」を明示、!Moveで「移動不可型」を表現
- Forgetトレイト で「この型はmem::forget可能」を明示、!Forgetで「忘却不可型」を表現
- 型が!Moveの場合、アドレスが生存期間中ずっと安定、Pinより単純
- !Forget型は必ずデストラクタが実行されるため、安全なscoped spawnやasync dropが可能
- Sized階層の拡張と同じ思想で、型の能力をトレイトで管理
モチベーションと課題
- 自己参照型 (例:多くのasync future)は移動不可が本質的要件
- Pinによる実装は複雑で、Linuxカーネルのような用途では安全性に限界
- 確実なデストラクタ実行 が必要な型(例:Transactionやscoped task handle)はmem::forgetで破壊されると安全性が損なわれる
- 現状のRustではscoped spawnなどのパターンが安全に実装できない
新トレイト導入の具体案
- Moveトレイト :移動可能性を型のプロパティに
#[lang = "move"] unsafe auto trait Move {}- !Move型は生涯同じアドレスを保持
- in-place初期化(#t-lang/in-place-init)が前提
- Forgetトレイト :忘却可能性を型のプロパティに
unsafe impl !Forget for ScopedTaskHandle {}- !Forget型は必ずデストラクタ実行
- 安全なscoped spawnパターンが可能(ハンドルdrop時に必ずjoin)
今後1年の主な作業
- Moveトレイトのコンパイラ実装・RFC執筆・Linuxカーネル実地検証
- Iteratorと!Move型の相互作用検証(自己参照を含むgenerator効果のサポート)
- Guaranteed destructors設計検討(既存機能とのトレイト階層の調整)
スコープ外事項
- Futureトレイト の変更や移行は今回は対象外
- Pin依存以外にも多くの課題があるため、将来の独立プロジェクト扱い
よくある質問(FAQ)
-
Sized階層との関係 型の能力(サイズ・移動・忘却)をトレイト階層で明示的に管理する流れの一部
-
Pinエルゴノミクスとの違い Pinの複雑さ(Trait/PinnedTraitの重複・Dropの特例など)を根本解決するため、Pin自体を将来的に非推奨にする方針
-
安全なscoped spawnの実現要件 !Forget型により、ハンドルのデストラクタが必ず走る=join保証ができる
-
参考ブログ・設計案
- Move, Destruct, Leak:デストラクタ・忘却トレイト階層の考察
- Must move types:呼び出し側に特定のアクションを強制する型設計
- Ergonomic Self-Referential Types for Rust:Moveトレイトの設計詳細
- Why Pin is a part of trait signatures:Pinの課題と本提案の動機
- Placing functions:!Move型のin-place構築構文案
今後の展望
- Pinの複雑さから脱却し、 型の能力を明示的にトレイトで管理 するRustへ進化
- 自己参照型・スコープ付き非同期タスク など、これまで難しかった安全パターンの普及促進
- 既存コードとの互換性維持を重視しつつ、段階的な導入と検証を推進