Files
hakorune/docs/ideas/other/2025-08-25-unified-box-design-deep-analysis.md
Moe Charm 378a2bc174 LoopBuilder: bind variable_map to Phi result on seal
- After inserting Phi at loop header, update variable_map so that
  subsequent uses (after the loop) refer to the Phi result instead of
  the latch/body value. This fixes dominance issues in verifier.
- Add tests: loop phi normalization and loop+nested-if phi; both pass.
2025-08-26 06:35:39 +09:00

16 KiB
Raw Blame History

Nyash統一Box設計の深い分析と今後の方向性

Status: Research Created: 2025-08-25 Priority: High Related: Everything is Box哲学の実装レベルでの完全実現

現状の統一Box設計

3種類のBoxの存在

  1. ビルトインBox - Rustで実装StringBox, IntegerBox, ConsoleBox等
  2. プラグインBox - 動的ライブラリで提供FileBox等の置き換え可能
  3. ユーザー定義Box - Nyashコードで定義box Person等

現在の統一アーキテクチャ

UnifiedBoxRegistry統一レジストリ
├── BuiltinBoxFactory優先度1
├── UserDefinedBoxFactory優先度2
└── PluginBoxFactory優先度3

統一の美しさ

  1. 透過的な置き換え

    • 同じ名前のBoxをプラグインで上書き可能
    • 実行時の動的切り替えも可能
  2. 統一インターフェース

    pub trait BoxFactory: Send + Sync {
        fn create_box(&self, name: &str, args: &[Box<dyn NyashBox>]) -> Result<Box<dyn NyashBox>, RuntimeError>;
        fn box_types(&self) -> Vec<&str>;
        fn supports_birth(&self) -> bool;
    }
    
  3. 優先順位システム

    • ビルトイン > ユーザー定義 > プラグイン
    • 予約語保護StringBox等は上書き不可

InstanceBoxによる完全統一

統一実装の核心

pub struct InstanceBox {
    pub class_name: String,                       // "StringBox", "Person"等
    pub inner_content: Option<Box<dyn NyashBox>>, // 内包Box統一
    pub fields_ng: Arc<Mutex<HashMap<String, NyashValue>>>,
    pub methods: Arc<HashMap<String, ASTNode>>,
}

3つの形態を統一的に扱う

// ビルトイン
InstanceBox::from_any_box("StringBox", Box::new(StringBox::new("hello")))

// プラグイン
InstanceBox::from_any_box("FileBox", plugin_loader.create_box("FileBox"))

// ユーザー定義
InstanceBox::from_declaration("Person", vec!["name", "age"], methods)

基本メソッドの統一提案

問題点

  • toString()to_string_box() Rustの命名規則で異なる
  • type()type_name() (微妙に異なる)
  • 各Boxで個別実装されていて統一感がない

解決案NyashBoxトレイトにデフォルト実装

pub trait NyashBox: BoxCore + Debug {
    // Nyash標準メソッドデフォルト実装
    fn toString(&self) -> Box<dyn NyashBox> {
        Box::new(StringBox::new(&self.to_string_box().value))
    }
    
    fn type(&self) -> Box<dyn NyashBox> {
        Box::new(StringBox::new(self.type_name()))
    }
    
    fn equals(&self, other: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
        Box::new(BoolBox::new(self.equals_internal(other.as_ref())))
    }
    
    fn clone(&self) -> Box<dyn NyashBox> {
        self.clone_box()
    }
}

VMでの統一的な呼び出し

pub(super) fn call_box_method(&self, box_value: Box<dyn NyashBox>, method: &str, args: Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, VMError> {
    // 基本メソッドは全Boxで使える
    match method {
        "toString" => Ok(box_value.toString()),
        "type" => Ok(box_value.type()),
        "equals" => Ok(box_value.equals(args[0].clone_or_share())),
        "clone" => Ok(box_value.clone()),
        _ => self.call_specific_method(box_value, method, args)
    }
}

Gemini先生からの提案部分

1. NyashValue Enumの導入

pub enum NyashValue {
    // 即値(スタック上)
    Void,
    Bool(bool),
    Integer(i64),
    Float(f64),
    
    // ヒープ上の不変値
    String(Arc<String>),
    
    // 複雑なオブジェクト
    Object(Arc<NyashObject>),
}

メリット:

  • 小さな値のヒープアロケーション回避
  • パターンマッチによる高速ディスパッチ
  • 型安全性の向上

2. トレイトの階層化

// 基本トレイト
pub trait NyashBox: Send + Sync + Debug {
    fn to_string(&self) -> String;
    fn type_name(&self) -> &'static str;
    fn equals(&self, other: &dyn NyashBox) -> bool;
}

// 拡張トレイト
pub trait Comparable: NyashBox {
    fn compare(&self, other: &dyn NyashBox) -> Option<Ordering>;
}

pub trait Arithmetic: NyashBox {
    fn add(&self, other: &dyn NyashBox) -> Result<Box<dyn NyashBox>, String>;
}

3. メタプログラミング機能

pub trait BoxMetadata {
    fn on_method_missing(&self, name: &str, args: &[NyashValue]) -> Option<NyashValue>;
    fn on_field_access(&self, name: &str) -> Option<NyashValue>;
}

統一継承の実現

現在の課題 → 2025-08-25更新すべて実装済み

  • ビルトインBoxの継承ができない 実装済み!
  • プラグインBoxの継承も未実装 実装済み!

理想的な統一継承(すでに実現!)

// すべて可能になった!
box MyString from StringBox { }      // ビルトイン継承 ✅
box MyFile from FileBox { }          // プラグイン継承 ✅ 
box Employee from Person { }         // ユーザー定義継承 ✅

// 多重デリゲーションも可能!
box MultiChild from StringBox, IntegerBox { }  // ✅

実際のコード例(動作確認済み)

box EnhancedString from StringBox {
    init { prefix, suffix }
    
    birth(text) {
        from StringBox.birth(text)  // 透過的にpackに変換される
        me.prefix = "【"
        me.suffix = "】"
    }
    
    enhanced() {
        return me.prefix + me.toString() + me.suffix + "✨"
    }
}

さらなる美化への道

1. パイプライン演算子

// 現在
local result = str.substring(0, 5).toUpperCase().trim()

// パイプライン版
local result = str
    |> substring(0, 5)
    |> toUpperCase()
    |> trim()

2. Box階層の整理

NyashBox (trait)
├── ValueBox (数値・文字列・真偽値)
│   ├── IntegerBox
│   ├── StringBox
│   └── BoolBox
├── ContainerBox (コレクション)
│   ├── ArrayBox
│   └── MapBox
├── IOBox (入出力)
│   ├── ConsoleBox
│   └── FileBox
└── ConcurrentBox (並行処理)
    ├── FutureBox
    └── ChannelBox

3. エフェクトシステムの美化

impl ArrayBox {
    #[effect(Pure)]
    fn length(&self) -> IntegerBox { }
    
    #[effect(State)]
    fn push(&mut self, item: Box<dyn NyashBox>) { }
}

実装優先順位80/20ルール

今すぐやるべき80%

  1. 基本メソッドtoString, type, equals, cloneの統一実装
  2. VMでの統一的なメソッドディスパッチ
  3. InstanceBoxのinner_content活用の徹底

後でじっくり20%

  1. NyashValue enum導入によるパフォーマンス最適化
  2. トレイト階層化による整理
  3. パイプライン演算子の実装
  4. メタプログラミング機能
  5. 完全な統一継承システム

まとめ

現在のNyashの統一Box設計は、すでに相当美しく実装されている。特に

  1. UnifiedBoxRegistryによる透過的な管理
  2. 優先順位システムによる明確な解決
  3. InstanceBoxによる統一的な扱い

これらは「Everything is Box」哲学を実装レベルで体現している。

ユーザー定義Boxをビルトイン/プラグインBoxと完全に同じレベルで扱うことは、強引ではなく、むしろ設計として自然で美しい。この統一により、言語の一貫性と拡張性が大幅に向上する。

今後は、基本メソッドの統一実装から始めて、段階的により洗練された設計へと進化させていくのが良いだろう。

🚀 MIR/VM統一実装計画2025-08-25追記

📍 現状の課題

VMとMIRで、Box型によって異なる処理をしている

// VMでの現状InstanceBoxだけ特別扱い
if let Some(inst) = arc_box.as_any().downcast_ref::<InstanceBox>() {
    // ユーザー定義Box → 関数呼び出しに変換
    let func_name = format!("{}.{}/{}", inst.class_name, method, args.len());
} else {
    // ビルトイン/プラグイン → 直接メソッド呼び出し
    self.call_box_method(cloned_box, method, nyash_args)?
}

🎯 統一実装の提案

1. 統一メソッドディスパッチインターフェース

pub trait UnifiedBox: NyashBox {
    fn dispatch_method(&self, method: &str, args: Vec<Box<dyn NyashBox>>) 
        -> Result<Box<dyn NyashBox>, String> {
        // デフォルト実装:既存のメソッド呼び出しを使用
        self.call_method(method, args)
    }
}

// InstanceBoxでのオーバーライド
impl UnifiedBox for InstanceBox {
    fn dispatch_method(&self, method: &str, args: Vec<Box<dyn NyashBox>>) 
        -> Result<Box<dyn NyashBox>, String> {
        // MIR関数へのリダイレクト
        let func_name = format!("{}.{}/{}", self.class_name, method, args.len());
        // VM経由で関数呼び出し
    }
}

2. VMの簡素化

// 統一後:すべて同じ処理パス
let result = match &recv {
    VMValue::BoxRef(arc_box) => {
        arc_box.dispatch_method(method, nyash_args)?
    }
    _ => {
        recv.to_nyash_box().dispatch_method(method, nyash_args)?
    }
};

3. MIRレベルでの統一

  • BoxCall命令ですべてのBox型を統一的に処理
  • 型による分岐や特殊処理を削除
  • コンパイル時の最適化は維持

💎 期待される効果

  1. コードの簡素化

    • VM内の条件分岐削除で30%以上のコード削減
    • 新Box型追加時の変更箇所が最小限に
  2. 保守性の向上

    • Box型の実装詳細がVMから隠蔽される
    • テストが書きやすくなる
  3. パフォーマンス

    • 統一的な最適化(メソッドキャッシュ等)が可能
    • 仮想関数テーブルによる高速化の可能性
  4. 美しさ

    • 「Everything is Box」が実装レベルでも完全に実現
    • シンプルで理解しやすいコード

📅 実装ロードマップ

  1. Phase 1: UnifiedBoxトレイトの導入後方互換性を保ちながら
  2. Phase 2: VMでの統一ディスパッチ実装
  3. Phase 3: MIRビルダーの簡素化
  4. Phase 4: 旧実装の削除とクリーンアップ

🌟 最終的なビジョン

すべてのBoxビルトイン、プラグイン、ユーザー定義が完全に統一された世界

  • 同じインターフェース
  • 同じ実行パス
  • 同じ最適化機会

これこそが「Everything is Box」の究極の実現

🔌 プラグインローダーv2との統合

現在のプラグインシステムとの関係

  • プラグインローダーv2がすでに統一的なインターフェースを提供
  • extern_call経由での統一的なアクセス
  • UnifiedBoxトレイトとの相性は良好

統合のメリット

  • プラグインBoxもdispatch_method()で統一処理
  • ホットリロード時も透過的に動作
  • FFI境界を意識しない実装

📊 パフォーマンス測定計画

現在のベースライン

  • インタープリター基準で13.5倍高速化達成VM実装
  • BoxCall命令の実行時間が全体の約30%

統一実装後の予測

  • 条件分岐削減で5-10%の高速化期待
  • メソッドキャッシュで追加20%改善の可能性
  • 測定方法:--benchmark --iterations 1000で検証

🔄 移行時の互換性戦略

段階的移行計画

  1. Phase 1: UnifiedBoxトレイトを追加既存APIは維持
  2. Phase 2: 警告付きで旧API使用を通知
  3. Phase 3: 内部実装を統一版に切り替え
  4. Phase 4: 旧APIをdeprecated化
  5. Phase 5: 完全削除6ヶ月後

テスト戦略

  • 既存の全E2Eテストが通ることを保証
  • パフォーマンスリグレッションテスト追加
  • プラグイン互換性テストスイート

JITコンパイラとの統合Phase 9準備

統一メソッドディスパッチの利点

  • JITが最適化しやすい単純な呼び出しパターン
  • インライン展開の機会増加
  • 型情報を活用した特殊化

仮想関数テーブルvtable戦略

struct BoxVTable {
    methods: HashMap<String, fn(&dyn NyashBox, Vec<Box<dyn NyashBox>>) -> Result<Box<dyn NyashBox>, String>>,
}
  • 起動時に事前計算
  • JITコンパイル時に直接参照
  • キャッシュフレンドリーな配置

🔧 具体的な実装タスクTODO

Phase 1: 基礎実装1週間

  • UnifiedBoxトレイトの定義src/box_trait.rs
  • StringBox, IntegerBox等への実装
  • InstanceBoxへのdispatch_method実装
  • 単体テストの作成

Phase 2: VM統合2週間

  • execute_boxcall()の簡素化
  • InstanceBox特別扱いコードの削除
  • VMValueとの統合
  • E2Eテスト全パス確認
  • ベンチマーク実行と比較

Phase 3: 最適化1週間

  • メソッドキャッシュ実装
  • 頻出メソッドの特殊化
  • vtable事前計算
  • JIT統合準備

Phase 4: クリーンアップ3日

  • 旧実装コードの削除
  • ドキュメント更新
  • CHANGELOG記載
  • マイグレーションガイド作成

検証項目

  • 全Box型でtoString/type/equals/cloneが動作
  • プラグインBoxの透過的な動作
  • パフォーマンス改善の確認
  • メモリ使用量の変化なし

🚀 究極の統一ビルトインBox完全プラグイン化構想

現状の二重実装問題

  • plugin_loader.rs (1217行) - ビルトインBoxの動的ライブラリ化
  • plugin_loader_v2.rs (906行) - プラグインBoxシステム
  • 合計2000行以上の重複

完全プラグイン化の提案

すべてをプラグインに統一

// 現在
ビルトインFileBox  静的リンク
プラグインFileBox  動的ロード(.so

// 統一後
すべてのBox  プラグイン(.so)として実装

コアBoxの自動ロード戦略

const CORE_BOXES: &[&str] = &[
    "libnyash_string_box.so",   // StringBox必須
    "libnyash_integer_box.so",  // IntegerBox必須
    "libnyash_bool_box.so",     // BoolBox必須
    "libnyash_console_box.so",  // ConsoleBoxprint用
];

// 起動時に自動ロード
fn init_core_boxes() {
    for plugin in CORE_BOXES {
        plugin_loader.load_required(plugin)
            .expect("Core box loading failed");
    }
}

メリット

  1. コード削減: plugin_loader.rs (1217行) を完全削除
  2. 統一性: Everything is Boxの究極の実現
  3. 柔軟性: StringBoxすら置き換え可能
  4. ビルド高速化: 本体が軽量に
  5. 配布の柔軟性: 必要なBoxだけ選択可能

考慮事項

パフォーマンス

  • FFI境界のオーバーヘッドはナノ秒レベル
  • 実用上の影響なし

デバッグの課題と対策

// 課題:エラー時のスタックトレース
thread 'main' panicked at 'FFI boundary: 0x7f8b2c001234'

// 対策1プラグイン側でのロギング
#[no_mangle]
pub extern "C" fn box_method_toString() {
    eprintln!("[StringBox::toString] called from {:?}", std::thread::current().id());
}

// 対策2デバッグシンボル保持
cargo build --features debug-symbols

// 対策3プラグイン単体テストの充実
#[test]
fn test_string_box_methods() { /* ... */ }

実装ロードマップ

  1. Phase A: コアBoxのプラグイン化
    • StringBox, IntegerBox, BoolBox, ConsoleBox
  2. Phase B: 起動時自動ロード機構
  3. Phase C: plugin_loader.rs削除
  4. Phase D: ドキュメント・テスト整備

設定ファイル案

# ~/.nyash/config.toml
[plugins]
core_path = "./plugins/core/"
search_paths = ["./plugins", "/usr/lib/nyash/plugins"]

[core_boxes]
required = ["string", "integer", "bool", "console"]
optional = ["file", "math", "time"]

これにより、「Everything is Box」哲学が実装レベルでも完全に実現される