📘

【bugs.ruby Advent Calender】多重代入の話【22日目】

2024/12/01に公開

bugs.ruby Advent Calender 22日目の記事です。

これはなに

今年1年間通してみてきた bugs.ruby のチケットの中から気になったものを1つずつ取り上げていく Advent Calender です。
取り上げるチケットは基本的にこのブログで取り上げたものになります。
記事のまとめは ここを参照 してください。

[Bug #20858] multiple parallel assignments are inconsistent

Ruby の多重代入むずかしいよね、っていう内容です。

まず、次のように複数の代入式がある場合、これらは同じ値が代入されます。

a = b = c = 1
pp a:, b:, c:
# => {:a=>1, :b=>1, :c=>1}

また、次のように『1つの代入式でに複数の変数や値がある場合』にはそれぞれ別々の変数に値が代入されます。

a, b = 1, 2
pp a:, b:
# => {:a=>1, :b=>2}

これらを踏まえたときの次のような代入式の結果がどうなるのか、というのがこのチケットの内容になっています。

a, b = c, d = 3, 4

pp a:, b:, c:, d:
# => ???

チケットの起票者としてはまず c, d = 3, 4 が評価され、その上で a, b = が評価されることを期待しているんですが、実際にはこの挙動にはならずエラーになってしまいます。

a, b = c, d = 3, 4

# error: undefined local variable or method `c' for main (NameError)
pp a:, b:, c:, d:

なぜ、エラーになってしまうのかというと現状では a, b = c, d = 3, 4a, b = c, (d = 3), 4 のように解釈されてしまうからです。
なのでこれは次のように処理されます。

  1. d = 3 が処理される
  2. c, (d = 3), 4 の結果を a, b に代入する
  3. なので a = c b = (d = 3) としてそれぞれ代入されようとする
  4. しかし c は未定義なのでエラーになってしまう

ここまで踏まえるとわかるんですが a, b = c, d = 3, 4 だけみてもわからないですよねえ。

ちbなみに a = c = 3 b = d = 4 みたいな挙動になってほしい場合は以下のようなカッコをつけることで期待する代入になります

a, b = (c, d = 3, 4)

pp a:, b:, c:, d:
# => {:a=>3, :b=>4, :c=>3, :d=>4}

関連

GitHubで編集を提案

Discussion