So, I just read this blog post, and I was confused by the "ternary-operator is left-associative" part, so I ran the example code there-in in an interpreter:
$arg = 'T';
$vehicle = ( ( $arg == 'B' ) ? 'bus' :
( $arg == 'A' ) ? 'airplane' :
( $arg == 'T' ) ? 'train' :
( $arg == 'C' ) ? 'car' :
( $arg == 'H' ) ? 'horse' :
'feet' );
echo $vehicle;
and indeed, it returns horse
which is the counter-intuitiveness that was the point in the blog post.
Out of curiosity, I then tried to "make this work" by re-writing it to fit what I thought "left-associative" would want. I got this (formatting is weird, but it makes it clearer at least in MY head):
$arg = 'T';
$vehicle = ( ( $arg != 'B' ) ?
( $arg != 'A' ) ?
( $arg != 'T' ) ?
( $arg != 'C' ) ?
( $arg != 'H' ) ?
'feet' :
'horse' :
'car' :
'train' :
'airplane' :
'bus'
);
echo $vehicle;
Now, this works as expected in the sense that what ever character $arg
is returns the vehicle that begins with that character (lower case of course, but that's not important here).
Curious still, because I'm not clear on WHY the former does not work, I wondered if the latter will fail in a right-associative language, because it does not seem like it would. So I tested it in a java interpreter. Code here for anyone who wants to try and save a few seconds.
class Main {
public static void main(String[] args) {
Character arg = 'a';
String vehicle = ( ( arg == 'B' ) ? "bus" :
( arg == 'A' ) ? "airplane" :
( arg == 'T' ) ? "train" :
( arg == 'C' ) ? "car" :
( arg == 'H' ) ? "horse" :
"feet" );
System.out.println(vehicle);
vehicle = ( ( arg != 'B' ) ?
( arg != 'A' ) ?
( arg != 'T' ) ?
( arg != 'C' ) ?
( arg != 'H' ) ?
"feet" :
"horse" :
"car" :
"train" :
"airplane" :
"bus"
);
System.out.println(vehicle);
}
}
Both format works in java. So, what gives in php? I have heard that it is essentially evaluating the leading equalities as the final one ($arg == 'H'
). But if so, that means its behaving as though it was
$vehicle = ((($arg == 'B') || ($arg == 'A') || ($arg == 'T') ||
($arg == 'C') || ($arg == 'H')) ? 'horse' : 'feet');
This does not make sense to me. In the second php example I gave, I only moved where the equalities go, nesting in the if true
part of ternary expression, instead of the if false
part. I don't see why the first method would not work if the second does. This seems more like an error rather than "this is how it should work", and I'm just misinterpreting things, which I must be.
NOTE: I know I can just wrap parenthesis around things to force the expression to be evaluated the way I want (which apparently is right-associative). I am not looking for "how to make this work", I want to know why it does not.
Left- vs right-associative is about precedence when stringing multiple operators together, e.g. A + B + C
.
For the ternary operator A ? B : C
, this only has meaning when the extra ternary operator replaces the C
part (or A
part):
A ? B : X ? Y : Z
(A ? B : X) ? Y : Z <-- left-associative (PHP)
A ? B : (X ? Y : Z) <-- right-associative (Java, C, C++, C#, Perl)
If the extra ternary operator is inserted in the middle (replacing B
), it can only have one meaning:
A ? X ? Y : Z : C
A ? (X ? Y : Z) : C
That is why PHP and Java agree on the second one. There is no left-/right-associative rule applied.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With