多値 再考

これまで、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)