Files
hakorune/docs/private/papers/reference/boxes-system/delegation-system.md

8.1 KiB
Raw Blame History

🔄 Nyash デリゲーションシステム

📋 概要

Nyashは継承の代わりに「完全明示デリゲーション」を採用しています。 これは「Everything is Box」哲学に基づく、より安全で明確な設計アプローチです。

🎯 なぜデリゲーションか

継承の問題点

  1. 暗黙的な結合: 親クラスの変更が子クラスに予期せぬ影響
  2. 多重継承の複雑性: ダイヤモンド問題
  3. 実装の隠蔽: 何がどこから来ているか不明確

デリゲーションの利点

  1. 明示的: すべての委譲が明確に記述される
  2. 柔軟: 複数のBoxから選択的に機能を組み合わせ
  3. 安全: 予期せぬ副作用を防ぐ

🏗️ 基本構文

from構文によるデリゲーション宣言

// ParentBoxにデリゲート
box Child from Parent {
    init { childField }
    
    // 親のコンストラクタを呼ぶ
    pack(name, age, childData) {
        from Parent.pack(name, age)
        me.childField = childData
    }
}

override必須

box Child from Parent {
    // ❌ エラー: overrideキーワードが必要
    toString() {
        return "Child"
    }
    
    // ✅ 正しい: 明示的override
    override toString() {
        return "Child: " + from Parent.toString()
    }
}

📖 デリゲーションパターン

1. 基本的なデリゲーション

box Animal {
    init { name, species }
    
    pack(animalName, animalSpecies) {
        me.name = animalName
        me.species = animalSpecies
    }
    
    speak() {
        return me.name + " makes a sound"
    }
    
    toString() {
        return me.species + " named " + me.name
    }
}

box Dog from Animal {
    init { breed }
    
    pack(dogName, dogBreed) {
        from Animal.pack(dogName, "Dog")
        me.breed = dogBreed
    }
    
    override speak() {
        return me.name + " barks!"
    }
    
    // toStringは親のものをそのまま使用
}

2. 選択的メソッドオーバーライド

box EnhancedDog from Dog {
    init { tricks }
    
    pack(name, breed) {
        from Dog.pack(name, breed)
        me.tricks = new ArrayBox()
    }
    
    // speakは親のまま使用
    
    // toStringだけオーバーライド
    override toString() {
        local base = from Animal.toString()  // 祖父母から直接
        return base + " (Enhanced)"
    }
    
    // 新しいメソッド追加
    addTrick(trick) {
        me.tricks.push(trick)
    }
}

3. 複数Box組み合わせ予定機能

// 将来的な複数デリゲーション構想
box MultiChild from ParentA, ParentB {
    pack() {
        from ParentA.pack()
        from ParentB.pack()
    }
    
    methodA() {
        return from ParentA.method()
    }
    
    methodB() {
        return from ParentB.method()
    }
}

🌟 birth構文 - Box哲学の具現化

コンストラクタの優先順位

box User {
    init { name, email }
    
    // 優先度1: birth推奨
    birth(userName, userEmail) {
        me.name = userName
        me.email = userEmail
        print("🌟 " + userName + " が誕生しました!")
    }
    
    // 優先度2: initbirthがない場合
    init(name, email) {
        me.name = name
        me.email = email
    }
    
    // 優先度3: Box名互換性のため
    User(name, email) {
        me.name = name
        me.email = email
    }
}

// birthが優先的に使用される
local user = new User("Alice", "alice@example.com")

birth構文とデリゲーション

box Product {
    init { name, price }
    
    birth(productName, productPrice) {
        me.name = productName
        me.price = productPrice
        print("📦 Product created: " + productName)
    }
}

box DiscountedProduct from Product {
    init { discount }
    
    birth(name, originalPrice, discountPercent) {
        local discountedPrice = originalPrice * (1 - discountPercent / 100)
        from Product.birth(name, discountedPrice)  # 親のbirthを呼ぶ
        me.discount = discountPercent
    }
    
    originalPrice() {
        return me.price / (1 - me.discount / 100)
    }
}

🚨 pack構文 - ビルトインBox継承専用

重要: pack構文はビルトインBox継承専用です。ユーザー定義Boxでは使用しません。

# ✅ 正しい使い方ビルトインBox継承のみ
box EnhancedP2P from P2PBox {
    init { extraFeatures }
    
    pack(nodeId, transport) {
        from P2PBox.pack(nodeId, transport)  # ビルトインBoxの初期化
        me.extraFeatures = new ArrayBox()
    }
}

box CustomMath from MathBox {
    init { history }
    
    pack() {
        from MathBox.pack()  # ビルトインBoxの初期化
        me.history = new ArrayBox()
    }
}

# ❌ 間違いユーザー定義Boxでpack使用
box RegularUser {
    pack(name) {  # これは間違いbirth()を使う
        me.name = name
    }
}

🔍 from構文の詳細

メソッド内でのfrom使用

box Child from Parent {
    override process(data) {
        // 前処理
        local prepared = me.prepare(data)
        
        // 親の処理を呼ぶ
        local result = from Parent.process(prepared)
        
        // 後処理
        return me.postProcess(result)
    }
}

条件付きデリゲーション

box SmartChild from Parent {
    override calculate(value) {
        if value > 100 {
            // 大きな値は親に任せる
            return from Parent.calculate(value)
        } else {
            // 小さな値は自分で処理
            return value * 2
        }
    }
}

ベストプラクティス

1. 明示的なoverride

// ✅ 良い: 意図が明確
override toString() {
    return "Custom: " + from Parent.toString()
}

// ❌ 悪い: overrideなしはエラー
toString() {
    return "Custom"
}

2. 適切なデリゲーション粒度

// ✅ 良い: 必要な部分だけオーバーライド
box CustomList from ArrayBox {
    override push(item) {
        console.log("Adding: " + item)
        from ArrayBox.push(item)
    }
    // 他のメソッドはそのまま使用
}

// ❌ 悪い: すべてをオーバーライド
box BadList from ArrayBox {
    override push(item) { /* ... */ }
    override pop() { /* ... */ }
    override get(i) { /* ... */ }
    override set(i, v) { /* ... */ }
    // すべて再実装は無駄
}

3. デリゲーションチェーンの管理

// ✅ 良い: 明確な責任分離
box A {
    process() { return "A" }
}

box B from A {
    override process() {
        return from A.process() + "->B"
    }
}

box C from B {
    override process() {
        return from B.process() + "->C"
    }
}

// 結果: "A->B->C"

🚨 注意点

1. 循環デリゲーション禁止

// ❌ エラー: 循環デリゲーション
box A from B { }
box B from A { }  // コンパイルエラー

2. 多段デリゲーション制限

// 現在の制限
box A { }
box B from A { }
box C from B {
    method() {
        // ❌ エラー: CはAにデリゲートしていない
        from A.method()
        
        // ✅ OK: 直接の親
        from B.method()
    }
}

3. 動的デリゲーション不可

// ❌ エラー: デリゲーション先は静的に決定
box Dynamic from (condition ? A : B) { }

🔮 将来の拡張構想

1. 複数デリゲーション

box Multi from Network, Storage {
    save(data) {
        from Storage.save(data)
        from Network.sync(data)
    }
}

2. 条件付きデリゲーション

box Smart from Parent when Parent.version >= 2.0 {
    // バージョン対応
}

3. デリゲーションプロキシ

box Proxy delegates * to target {
    // すべてのメソッドを自動委譲
}

関連ドキュメント: