QA@IT

Rubyのメソッドの引数にandを使う場合に二重括弧が必要な理由

4301 PV

and を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
http://doc.ruby-lang.org/ja/1.9.3/doc/spec=2foperator.html

とドキュメントにあるのですが、その理由がわかりませんでした。
andのどのような性質のために二重括弧が必要になるんでしょうか?

  • コメントを受けて追記しました。 -
  • 回答コメントを追加しました。 -

回答

どのような性質なため

と、言われると評価優先度が低いからなのですが、

and、or は優先度が低いので自分の左右を先に解決してもらおうとします。

1 * 2 + 3 * 4

と書くと掛け算が優先されるのと同じですね。

def sample(a)
  p !a
end

このような関数があった場合に

sample true and false

と書いた場合、これは

(sample true) and false
(sample true) && false

と同じ結果になります。

一方

sample true && false

とした場合は

sample (true and false)
sample (true && false)

と同じ結果になります。

andやorが優先度が相当に低く設定されているため、andやorを評価する前に周りを評価しようとします。 andやorよりも関数の評価を先に行おうとしますが、そうすると文法的におかしいためにエラーになってしまうため、明示的にandやorを先に評価させるために括弧を書くわけです。


余談ですが優先度と括弧は等価ではありませんので

sample(true and false)

は上の例で示したように

(sample(true) and (false))

と、andの左右にある塊を括弧で括っても結果は同じになりません。
(運がいいのか悪いのか、意図と異なる形で文法的に問題なくなるため)

コメントを受けて追記しました

メソッドの sample(foo)sample fooが等価で二重括弧の一つ目は引数を表すための括弧で、もう一つがandを先に処理するための優先度変更のための括弧という理解であっているでしょうか?

その通りです。
ちなみに細かい話ですが
sample(foo)sample (foo) は異なる結果をもたらしますのでここも気を付けてください。

sample((true and false))
sample (true and false)

は等価です。二個目はメソッド名の次に空白がありますので、メソッドの引数を括る括弧は省略されたとみなされます。

sample(true and false)

はエラーです。括弧はメソッドの引数を括っているとみなされています。

メソッドの引数としてのスペースや括弧が && と and の中間の優先度だということだと思うのですが

スペースや括弧というよりはカンマの方が and/orよりも優先度が高いからかもしれません(引数が1つの場合はわかりにくいですが、perlが同様に notとandとorを持っていてこれがカンマより低いです。なお、perlとはいろいろ異なるのでエラーが出る出ないとか存在意義などはいろいろ異なると思います)。

引数が一つの場合は単にsample(3 if true) と似たような文法エラーという解釈でもいいじゃないでしょうかね。こちらは修飾子ですが sample((3 if true)) は同じように成功します。

rubyのドキュメントとしてそこまでの説明が存在するかどうかはわかりません(提示してくれていたリファレンスにある優先度しかないかもしれません)。

なお、rubyの and と orは優先度が同一のようなので、 && や || とは別の特殊なものと捉えた方がいいと思います。

# つまり以下は成り立たない。左はtrueで右はfalse。
( true || true && false) == (true or true and false)
編集 履歴 (2)
  • 回答ありがとうございます。まだ若干よくわかっていないのですが、メソッドの `sample(foo)` と `sample foo`が等価で二重括弧の一つ目は引数を表すための括弧で、もう一つがandを先に処理するための優先度変更のための括弧という理解であっているでしょうか? -
  • あとそれから、メソッドの引数としてのスペースや括弧が && と and の中間の優先度だということだと思うのですが、具体的に優先度のどこに位置するかとその機能の名称などはドキュメントに書かれていますか? -
  • 解説の追加ありがとうございます。`&&と||`に優先度の違いはあるのに`andとor`にはないんですね。気をつけてないとここもひっかかりそうです。`sample((3 if true))`ができることが驚きだったのですが、だとすると`sample (3 if true)`がエラーになるのがわかりません…。 -
  • `sample (3 if true)`がエラーになる -> ほんとですね、そこまでいくとパーサーを見ていくしかないとおもいますが、ifの左辺である `sample (3` を解決しようとするからだと思います。andは2項演算子ですが、ifは左側をもっと大きな範囲で評価しないといけないからでしょう。 -
  • andは2項演算子ですが-> 2項演算子なので、sample (true and false) とした場合、andの左側にあるtrueが決まればそれより手前をたどる必要がないから。という意味です。 -
  • なるほど、それぞれの評価範囲が異なるから起きるんですね。何度も解答ありがとうございました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。