読者です 読者をやめる 読者になる 読者になる

たごもりすメモ

コードとかその他の話とか。

andとorの優先順位についてハマる

ruby

うっかり以下のようなコードを書いた。意図は x が nil か、もしくは配列だけどサイズ 0 である場合を調べたかった。

if not x or x_is_list and x.size < 1
  ...
end

元はちょっと違うコードで、リファクタリングついでに上のようなコードに書き直して鼻歌まじりに spec を走らせてみたら NoMethodError: nil:NilClass has no method named 'size'。な、なぜだ…… nil の場合は 'not nil' が true になるんだからそれ以降は評価されないんじゃないの orz

とか思ってTwitterでたいへん騒いだわけだが*1。and/or演算子は && および || とは優先順位が違いますよ、というのは分かっていたつもりだったが、正確に理解していなかった。and と or の優先順位は正確に等しいので、上記のコードはつまり、以下のコードとイコールなわけだ。

if (((not x) or x_is_list) and x.size < 1)
  ...
end

こう書けば間違える人はおらんよなあ……。でも実質こうなので x_is_list が短絡評価により評価されないことはあるにしても x.size < 1 は必ず評価されるので x が nil なら当然例外になる。あああああ。

あまりに愚かな勘違いで大騒ぎしたが、自戒をこめてここに書いておく。and/orを使う場合は必ずカッコつきの式にすること。
とか考えてたら、なんかはるか昔にも同じような決意をしたような気のせいが……。Pythonを使ううちに忘れちゃったとかそういうオチだろうか。そうかもしれぬ。

*1:お騒がせいたしました