C言語の演算子の殆どは、評価順序が決まっていない。決まっているのは、
「,」「&&」「||」「?:」
PHP は決まっているのだろうか、と思って web のマニュアルを見ると、
次のように書いてある。
演算子の優先順位や結合性は、あくまでも式のグループ分けだけを決めるものであり、評価順を決めるものではありません。 PHP では一般に、式をどの順番で評価するかは決めていませn。 そのため、特定の順序で式が評価されることを前提としたコードを書いてはいけません。 PHP のバージョンが変わったり前後のコードが変わったりしたときに、評価順が変わる可能性があるからです。
(PHP: 演算子の優先順位 - Manual)
英文だとこうである。
Operator precedence and associativity only determine how expressions are grouped, they do not specify an order of evaluation. PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.
an order of evaluation は決まっていないというのである。
その後に例が出ているが、分かりにくい。
evaluation というのは、関数が呼ばれるところを想像すれば分かりやすい。
$i = (counter() + counter()) * counter();
counter() は、何度目に呼ばれたかというカウントを返す function だとする。
つまり、最初は1、2回目は2、3回目は3を返す。
どちらから呼ぶかというのが、order of evaluation である。
この例だと、左側から順に呼ばれたら、(1+2)*3=9 が $i に入る。
右側から呼ばれたら、(3+2)*1=6 になる。
order は決まっていないのだから、どちらになるか分からない。
括弧は、足し算を優先して計算する保証はするが、足し算の両側を先に呼び出すことまで保証しないのである。関数を全部呼び出してから計算するようになっているかもしれない。
そこで気になったのが、&& のような論理演算子である。
前述のように、C言語なら && は左から評価することが決まっているから、
if (0 && bar()) ..
この場合、0 を評価した時点で 0 && bar() の結果が 0 になることが確定する。
C言語の場合、このときに bar() は呼ばれない。
これを short-circuit evaluation (短絡評価)という…のだと長い間思っていた。
ひとまずそれを伏線にしておいて、
では、PHP だとどうなるか。
if (false && bar()) ..
false が先に評価されたら、その時点で、false && bar() の結果は確定する。
bar() の結果は関係ない。
しかし、先ほど紹介したように、PHP は演算子の評価順序を定めていない。
だから、もしかしたら bar() を先に呼び出して、true が返ってきてから false を評価しにいくかもしれない、と思ったわけだが、気になる記述がある。
// foo() will never get called as those operators are short-circuit
$a = (false && foo());
$b = (true || foo());
$c = (false and foo());
$d = (true or foo());
(PHP: Logical Operators - Manual)
PHP でも、この場合、foo() は呼ばないというのだ。
&& が short-circuit だという仕様がどこに出ているのか確認できなかったのだが、
私は今まで、short-circuit evaluation というのは、最初の評価で結果が確定したら次の評価をしないで結果とする、というような評価方法だと思っていた。
評価順序が定義されていない言語の場合、どういう順序で評価するか分からないが、AND ならどちらかが false になった時点で残りは省略する、というような処理だと思ったのである。
この解釈だと、
PHP で && が short-circuit だと言われても、どちらを先に評価するか分からないのだから non-sense じゃないの、と思ったのである。
そこで、盲信するのは危険だという承知の上で、Wikipedia の Short-circuit evaluation の記述を見ると、こんな表現になっている。
the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true
(Short-circuit evaluation - Wikipedia, the free encyclopedia)
the second というのは2番目、the firstというのは最初、というのは当然として、最初というのは何なのかという話。
つまり、この定義であったとして、右から左、right to left の順に evaluate するような programming language があったら、right が the first になるような可能性はあるのか?
それとも、the first というのはプログラムを目で追うときに最初に出現するところの、必ず左側の argument を指すことになるのだろうか?
endian の話じゃないけど。右が最下位なのか、最上位なのか、みたいな。
もし the first というのが見た目の最初、つまり left side という意味なら、私の今までの理解とはちょっと違うことになるし、PHP のマニュアルの内容も筋は通るのかもしれない。
とはいっても、他の演算子はともかく、PHP も含めて、&& や || を右から評価する言語というのは今までに遭遇したことがないし、これからもないような気がしますね。何となくだが。
並列処理的には、こういう演算子の evaluation order が決まっていないのなら、同時にやりたくなったりするかもしれないけど。カウントを返す関数が同時に呼ばれるなんてのは、かなり頭痛い話だけど。
にしても、短絡評価って表現、何かいいよね。
うっかりさんというか、はやとちりっぽくて。