演算子と優先順位

今日はちょっとだけ目新しい機能の紹介をします。


Xtalはちゃんと演算子に優先順位がついています。例えば+と*は、*の方が優先順位が高いため

  10 + 5 * 3

は、5*3が先に計算されて、10+15が計算されます。

良くあるほかの言語のように、括弧を使えば、+を先に計算するようにコントロールできます。

  (10 + 5) * 3

そして、Xtalは独自の演算子優先順位のコントロールを提供しています。

  10+5 * 3

このように、先に計算させたい方をくっつけて書くことで優先順位が一回り高くなるようになります。
逆に言うと、優先順位を低くしたい場合は、離して書くということです。くっつけて書くと、先に計算されるというのは見た目にマッチしていて直感的です。
間を空けすぎて、まさに間抜けなソースコードにならないよう、空白は二つ以上書いても、一つ書いたのと同じ分しか優先順位が低くならないルールがあります。

さてこの機能は「意図せず優先順位が変わることもあるんじゃないだろうか?」と心配される方がいるかもしれません。そのためどのような書き方でそういうことが良く起こりそうかを世の中のソースを調べたりして研究しました。

次の二つのケースは意図せず書いてしまうことがありそうだと感じました。

  • a=10 + 20; // (a=10) + 20となる?
  • a + 10==20 - b // a + (10==20) -bとなる?

つまり、代入と比較演算子です。Xtalでは代入は文で、(a=10)となることはありえません。

そして、下の比較演算子の例はコンパイラが許容しません。Xtalでは、比較演算子の結果をさらに計算するような式の形にすることは、コンパイルエラーになるようにしました。

  (10 == 5) + 5; // コンパイルエラー
  (5 < 10) + 20; // コンパイルエラー
  if(a < b < c){} // コンパイルエラー

これ以外の演算のケースでは、この空白による優先順位のコントロールは逆にバグを発生しづらくなると考えます。例えばC言語で、次のような間違いを起してしまった人は少なくないと思います。

 a + b<<2

シフト演算子が予想以上に優先順位が低いことを忘れてしまうバグです。
くっつけて書いため、見た目でb<<2が先に計算される、と脳内で解釈して素通りしてしまい発見が困難になることも、ありました。これは[ゲシュタルトの法則 近接の要因:http://ja.wikipedia.org/wiki/%E3%82%B2%E3%82%B7%E3%83%A5%E3%82%BF%E3%83%AB%E3%83%88%E5%BF%83%E7%90%86%E5%AD%A6]でも言われており、空白による優先順位のコントロールは理にかなってると思ってます。

例:

  10/2 .times{ |i| println(i); } // 0〜4までの数字が出力される
  println(1+1 * 2+2); // 8