今の多値の仕様と、Rubyの多値の仕様の比較

現在の実装では、「呼び出し側が必要とする戻り値の数」よりも関数が返す多値が多い場合、余った部分を配列に纏めるようになっています。

values: fun(){ return 0, 1, 2; }

// 多値を返すことと、配列を返すことは意味的には等しいので次のように定義できる
// ただし、多値の方が無駄な配列が生成されないので実行効率はよい
// values: fun(){ return [0, 1, 2]; }

{
  a: values();
  a.p; //=> [0, 1, 2]
}

{
  a, b: values();
  a.p; //=> 0
  b.p; //=> [1, 2]
}

{
  a, b, c: values();
  a.p; //=> 0
  b.p; //=> 1
  c.p; //=> 2
}

Rubyで書くと次のようになります

def values
  return 0, 1, 2

  # 配列で返しても同じ挙動となる
  # return [0, 1, 2]
end

a = values
p a #=> [0, 1, 2]

a, *b = values
p a #=> 0
p b #=> [1, 2]

a, b, c = values
p a #=> 0
p b #=> 1
p c #=> 2


Xtalは、多重代入とブロックパラメータへの代入の規則はまったく同じとなります。

foo: fiber{
  yield 0, 1, 2
 
  // 配列で返しても同じ
  // yield [0, 1, 2];
}

foo{ |a|
 a.p; //=> [0, 1, 2]
}

foo{ |a, b|
  a.p; //=> 0
  b.p; //=> [1, 2]
}

foo{ |a, b, c|
  a.p; //=> 0
  b.p; //=> 1
  c.p; //=> 2
}


Ruby*1は、多重代入とブロックパラメータへの代入は、細かく規則が変わり、混乱します*2

def foo
  yield 0, 1, 2
end

foo{ |a|
  # warning: multiple values for a block parameter (3 for 1)
  p a #=> [0, 1, 2]
}
# 怒られました。これは次のように書かなければならないようです。
foo{ |*a|
  p a #=> [0, 1, 2]
}
# しかし、多重代入の場合では、*a = values と書くと a は [[0, 1, 2]] となってしまうため、
# a = values と書く必要があります


# さらに、returnの場合では多値を返すことと、配列を返すことで挙動は変わりませんでしたが、
# yieldは配列を返すと挙動が変わります
def foo
  yield [0, 1, 2]
end

foo{ |*a|
  p a #=> [[0, 1, 2]]
}

# こんどは次が正解
foo{ |a|
  p a #=> [0, 1, 2]
}

*1:1.8.6で試しました

*2:私は