⚠️ 廃止 (DEPRECATED)
本 RFC は RFC-024:新並行モデル に置き換えられました。
RFC-001 の3層並行アーキテクチャ(L1/L2/L3)、@block/@eager アノテーション、DAG 自動解析などの設計は削除されました。新設計では
spawn {}ブロックを唯一の並行プリミティブとして使用し、アノテーションは不要です。本文書は歴史的参考のためにのみ保持されています。
title: "RFC-001:並作モデルとエラー処理システム"
RFC-001:並作モデルとエラー処理システム
設計ソース
| ドキュメント | 関係 |
|---|---|
| async-whitepaper | 設計ソース、理論的基盤 |
| language-spec | 規範目標 |
概要
YaoXiang の並作モデルを提案する:同期構文でロジックを記述し、ランタイムで自動的に並行実行する。コアメカニズム:3層並行アーキテクチャ + DAG 依存性解析 + Result 型システム。
クイック選択
| シナリオ | 記述方法 | 説明 |
|---|---|---|
| 自動並行 | アノテーションなし(デフォルト) | 最大並行性を実現 |
| 同期待機 | @eager | 依存関係の完了を待機 |
| 完全順序 | @block | 並行なし、デバッグ用 |
| 部分的並行 | spawn | @block スコープ内の並行 |
動機
現在の主流言語の並行モデルには明確な欠陥がある:
| 言語 | 並行モデル | 問題 |
|---|---|---|
| Rust | async/await + tokio | 非同期伝染、学習曲線が急 |
| Go | goroutine | 型安全性なし |
| Python | asyncio | GIL の制限 |
| JavaScript | Promise/async | コールバックが複雑 |
コアな矛盾
- 透明性 vs 制御性:完全透過だが制御不可 vs 完全制御可能だが不透明
- 並行 vs デバッグ可能性:並行プログラムはデバッグが難しい vs デバッグ可能なプログラムは並行にしにくい
提案
1. 並作モデル:3層並行アーキテクチャ
説明:L1/L2/L3 はメンタルモデルであり、ユーザーが異なるシナリオを理解するのに役立つ。実際の実装は1つのメカニズムのみ:DAG 自動解析 + アノテーション制御。
| 階層 | メンタルモデル | 構文 | 実行方式 | 並行度 |
|---|---|---|---|---|
| L1 | 並行禁止 | @block | 純粋な逐次実行 | ❌ なし |
| L2 | @block 内の並行 | spawn | @block スコープ内の制御可能な並行 | ⚠️ 一部 |
| L3 | 完全並行 | デフォルト(アノテーションなし) | DAG の自動解析 | ✅ 完全 |
L1: @block 同期モード
yaoxiang
main: () -> Void @block = {
data1 = fetch_sync("api1")
data2 = fetch_sync("api2")
process(data1, data2) # 厳密な順序、並行なし
}L2: @block 内の制御可能な並行
yaoxiang
# spawn は @block 関数内部でのみ使用可能
main: () -> Void @block = {
spawn { data1 = fetch_data("api1") }
spawn { data2 = fetch_data("api2") }
# すべての spawn の完了を待機(標準ライブラリが制御)
process(data1, data2)
}L3: 完全透過(デフォルト)
yaoxiang
# アノテーションは不要、コンパイラが自動的に DAG を解析
heavy_calc: (n: Int) -> Int = fibonacci(n)
auto_parallel: (n: Int) -> Int = {
a = heavy_calc(1) # 自動並行
b = heavy_calc(2) # 自動並行
c = heavy_calc(3) # 自動並行
a + b + c # 値が必要時にすべての結果を待機
}2. アノテーションの完全な比較
| 区分 | デフォルト(アノテーションなし) | @eager | @block | spawn |
|---|---|---|---|---|
| 実行方式 | 自動 DAG 解析 | 依存関係の同期待機 | 純粋順序 | @block 内の並行 |
| 並行度 | ✅ 完全 | ⚠️ 依存関係の順序に従う | ❌ なし | ⚠️ 一部 |
| DAG 構築 | ✅ | ✅ | ❌ | ✅ |
選択ガイド:
- 最大並行性 → アノテーションなし(デフォルト)
- 順序付き副作用が必要 →
@eager - デバッグ/新手/重要コード →
@block - @block 内で並行が必要 →
spawn
yaoxiang
# デフォルト:最大並行性を実現
calc_all: () -> Int = {
a = heavy_calc(1) # 自動並行
b = heavy_calc(2) # 自動並行
a + b
}
# @eager:同期待機
calc_seq: () -> Int @eager = {
a = heavy_calc(1) # 同期実行
b = heavy_calc(2) # 同期実行
a + b
}
# @block:純粋順序
calc_simple: () -> Int @block = {
a = heavy_calc(1) # 強制的に同期
b = heavy_calc(2) # 同期
a + b
}
# spawn:@block 内の並行
calc_mixed: () -> Int @block = {
spawn { heavy_calc(1) }
spawn { heavy_calc(2) }
heavy_calc(3) # 同期
}3. DAG 依存性解析
3.1 コア原則:ボトムアップ実行
ユーザーコード(同期構文):
a = fetch(url0)
b = fetch(url1)
print(a)
コンパイル時解析(ボトムアップ):
print(a) は a を必要とする → fetch(url0) に依存
fetch(url1) は誰も必要としていない → 孤立 DAG
ランタイムスケジューリング(叶子から開始):
fetch(url0) → print(a) ← 依存チェーン、順序通り
fetch(url1) ← 孤立、独立並行重要な洞察:「トップダウン」で Future を生成するのではなく、「ボトムアップ」で結果から逆算して依存関係を解析する。
3.2 孤立 DAG:独立並行
メインフロー:fetch(url0) → process → print
孤立: fetch(url1) ← 誰も結果を必要としていない、独立並行
スケジューラー:メインフローは依存チェーンに従って実行、孤立は別コアで並行3.3 リソース型と副作用
コアな考え方:リソース操作は型でマークされ、DAG が自動的に依存関係を構築する。同一リソースは自動的に直列化され、異なるリソースは自動的に並行実行される。
リソース型の境界——明確な定義:
リソース型はコンパイラの組み込みマーキングされた型である。以下の型はコンパイラによってリソースとして認識される:
| リソース型 | 説明 | コンパイラの動作 |
|---|---|---|
FilePath | ファイルシステムパス | 同一パス操作は自動的に直列化 |
HttpUrl | HTTP エンドポイント | 同一 URL 操作は自動的に直列化 |
DBUrl | データベース接続 | 同一接続操作は自動的に直列化 |
Console | 標準出力 | すべての Console 操作は自動的に直列化 |
ユーザー定義のリソース型は明示的にマーキングする必要がある:
yaoxiang
Database: Resource # リソース型として明示的にマーキング
query: (Database, String) -> Result(Row, Error)
# パラメータ Database は Resource で自動的にリソース操作として識別Resource マーキングのない型は、コンパイラによってリソース依存性が追跡されない。
使用ルール:
- 変数を介してリソースハンドルを渡し、DAG が自動的に順序を管理する
- リテラルを直接使用して同一リソースを使用するのはユーザーの設計上の問題であり、言語の責任ではない
yaoxiang
# ✅ 正しい:変数による渡し、DAG が自動的に直列化
filename: String = "data.txt"
File.write(filename, x)
File.write(filename, y) # DAG が直列化
# ⚠️ ユーザーの責任:リテラル
File.write("data.txt", x)
File.write("data.txt", y) # 並行になる可能性、ユーザーは自己責任3.4 無限ループ処理
1 つのループ → 直接的に同期実行、ゼロスケジューリングオーバーヘッド
複数のループ → スケジューラーがスライスを切り替え、真の並行性4. Result 型とエラー処理
yaoxiang
Result: (T: Type, E: Type) -> Type = { ok: (T) -> Self, err: (E) -> Self }
# ? 演算子の透過的な伝播
process: () -> Result(Data, Error) = {
data = fetch_data()?
processed = transform(data)?
save(processed)?
}5. DAG ノード設計
rust
enum NodeKind {
Task, // タスクノード
Value, // 値ノード
Control, // 制御フローノード
}
struct Node {
id: NodeId,
kind: NodeKind,
inputs: Vec<ValueNodeId>, // 入力依存
outputs: Vec<ValueNodeId>, // 出力値
span: Span, // ソースコードの位置
}| 辺の種類 | 記号 | セマンティクス |
|---|---|---|
| DataEdge | → | データ依存(値の流動) |
| ControlEdge | ● | 制御依存(順序実行) |
| SpawnEdge | ◎ | 並行エントリ(並列可能な開始点) |
6. 型システム
Send → スレッド間を安全に転送可能
Sync → スレッド間を安全に共有可能
Arc(T) は Send + Sync を実装(スレッドセーフ参照カウント)トレードオフ
利点
- 漸進的な採用:3層モデルが異なるスキルレベルに対応する
- 自然な構文:同期コードが並列性能を獲得する
- コンパイル時の安全性:Send/Sync 制約がデータ競合を消除する
- デバッグ可能性:エラーグラフが明確なエラー伝播ビューを提供する
欠点
- 学習曲線:DAG 依存の概念を理解する必要がある
- コンパイル時間:全プログラム DAG 解析は遅い可能性がある
- ツールチェーンの複雑性:新しいデバッグと可視化ツールが必要
代替案
| 方案 | 選択しない理由 |
|---|---|
| 明示的な async/await のみサポート | 透過的な並行を実現できない |
| 完全透過的な並行のみサポート | ユーザーが制御権を失う |
| Go スタイルの goroutine | 型安全性なし、コンパイル時チェック不可 |
| L1 モードのみ | 並作モデルのコアバリューを放棄 |
実装戦略
段階的区分
- 段階 1 (v0.1):@block 同期モード、基本型
- 段階 2 (v0.2):FlowScheduler スケジューラー
- 段階 3 (v0.3):spawn ブロック、明示的な並行
- 段階 4 (v0.5):L3 完全透過、DAG 自動解析
- 段階 5 (v0.6):エラーグラフ、グラフデバッガー
- 段階 6 (v1.0):本番使用可能な最適化
依存関係
- RFC-001 には外部依存なし(基本コア)
- RFC-008(Runtime 並行モデル)→ 設計完了
- RFC-011(泛型システム)→ 設計完了
リスク
- DAG 解析性能:全プログラム解析は O(n²) 可能性があり、最適化が必要
- ツールチェーンの欠如:デバッガーをゼロから開発する必要がある
- ユーザー受容性:透過的な並行性には適切なドキュメントが必要
設計決定記録
| 決定 | 決定 | 日付 |
|---|---|---|
| 3層並行アーキテクチャ | L1/L2/L3 漸進式 | 2025-01-05 |
| @block アノテーション位置 | 戻り値型の後 | 2025-01-05 |
| DAG エラー伝播 | 依存辺に沿って上流に伝播 | 2025-01-06 |
| DAG 性能最適化 | 増分構築 + キャッシュ | 2025-01-06 |
| ランタイム選択 | 泛型 + コンパイル時注入 | 2025-01-06 |
| ノードインターフェース | 泛型 + 関数注入(trait なし) | 2025-01-06 |
| エラーグラフメモリ | DAG は単一関数内でのみ構築 | 2025-01-06 |
| リソース競合検出 | DAG データフロー依存、ユーザーの変数渡し | 2025-01-06 |
| リソース型システム | Resource マーキング + DAG 自動依存 | 2026-01-06 |
| L1/L2/L3 メンタルモデル | 3層抽象化、実装メカニズムではない | 2026-01-06 |
| @auto アノテーション | 削除、デフォルト動作と重複 | 2026-05-11 |
| L1 自動フォールバック | 削除、動作が予測できない | 2026-05-11 |
付録:用語集
| 用語 | 定義 |
|---|---|
| 並作モデル | YaoXiang の並行パラダイム:同期構文、非同期の本質 |
| DAG | 有向無環図、計算依存関係を記述 |
| spawn | @block スコープ内の制御可能な並行 |
| @block | 同期アノテーション、並行最適化を無効化 |
| @eager | 熱心な評価、依存関係の完了を待機 |
| Resource | リソース型マーキング、操作が自動的に DAG 依存を構築 |
| エラーグラフ | 可視化されたエラー伝播パス |
