多値 再考
これまで、Xtalにおいて多値と配列は同じものである、と定義して、配列と多値が区別できない仕様にしていたのですが、ちょっと実装が難しい事例があったので、この仕様を見直すことにしました。
新しい仕様は次の通りです。
- 配列か多値かを区別できるようにするため、Arrayクラスを継承したMultiValueクラスを導入
- また、「何も返さない」という状態もあらわせるようにするため、undefined値も導入
挙動は次のようになります。
// 値を返さない関数を定義 return_nothing: fun(){} // 単値としてnullを返す関数を定義 return_null: fun(){ return null; } // 多値を返す関数を定義 return_mv: fun(){ return 5, 4, 3; } // 多値の最後がまた多値な値を返す関数を定義 return_mv2: fun(){ return 7, 6, return_mv(); } // 無値を単値として評価すると、undefinedとなる a: return_nothing(); //=> a = undefined; // 無値を多重代入で受け取ると、全てundefinedとなる a, b: return_nothing(); //=> a = undefined, b = undefined; // 単値を単値として評価すると、そのままその値が使われる a: return_null(); //=> a = null; // 単値を多重代入で受け取ると、一つ目の変数に値が入り、後はundefinedで補われる a, b: return_nothing(); //=> a = null, b = undefined; // 多値を単値として評価すると、全体がMultiValueオブジェクトとなる a: return_mv(); //=> a = (5, 4, 3) // 多値を少ない数の多重代入で受け取ると、最後の変数にMultiValueオブジェクトとして纏められる a, b: return_mv(); //=> a = 5, b = (4, 3) // 多値を同じ数の多重代入で受け取ると、全て単値として代入される a, b, c: return_mv(); //=> a = 5, b = 4, c = 3 // 多値を多い数の多重代入で受け取ると、全て単値として代入され、足りない部分はundefinedで補われる a, b, c, d: return_mv(); //=> a = 5, b = 4, c = 3, d = undefined // 最後の値が多値の場合、それは展開されて代入される a, b, c, d, e: return_mv2(); //=> a = 7, b = 6, c = 5, d = 4, e = 3 // 最後の値が多値で、余る場合、余った部分がMultiValueとして纏められる a, b, c, d: return_mv2(); //=> a = 7, b = 6, c = 5, d = (4, 3)
無値、単値、多値、それぞれを区別することなく扱うことが出来るようにするために、to_mvメソッド、flatten_mvメソッド、flatten_all_mvメソッドがAnyクラスなどに追加されます。
- to_mvメソッドは、
- 無値を要素0のMultiValueオブジェクトに、
- 単値を要素1のMultiValueオブジェクトに、
- 多値をそのままMultiValueオブジェクトにして返します。
- flatten_mvメソッドは、to_mvした後、MultiValueの最後の要素にMultiValueがある場合にそれを展開し、平らとなMultiValueオブジェクトにして返します。
- flatten_all_mvメソッドは、to_mvした後、MultiValueのそれぞれの要素にMutiValueがある場合にそれを展開し、完全に平らなMultiValueオブジェクトにして返します。
return_mv3: fun(){ return return_mv(), return_mv(), return_mv(); } return_nothing().to_mv; //=> () return_null().to_mv; //=> (null) return_mv().to_mv; //=> (5, 4, 3) return_mv2().to_mv; //=> (7, 6, (5, 4, 3)) return_mv3().to_mv; //=> ((5, 4, 3), (5, 4, 3), (5, 4, 3)) return_nothing().flatten_mv; //=> () return_null().flatten_mv; //=> (null) return_mv().flatten_mv; //=> (5, 4, 3) return_mv2().flatten_mv; //=> (7, 6, 5, 4, 3) return_mv3().flatten_mv; //=> ((5, 4, 3), (5, 4, 3), 5, 4, 3) return_nothing().flatten_all_mv; //=> () return_null().flatten_all_mv; //=> (null) return_mv().flatten_all_mv; //=> (5, 4, 3) return_mv2().flatten_all_mv; //=> (7, 6, 5, 4, 3) return_mv3().flatten_all_mv; //=> (5, 4, 3, 5, 4, 3, 5, 4, 3)