This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pod/perlop.pod: expand doc on chained comparisons
authorZefram <zefram@fysh.org>
Fri, 7 Feb 2020 09:30:21 +0000 (09:30 +0000)
committerKarl Williamson <khw@cpan.org>
Fri, 13 Mar 2020 04:34:26 +0000 (22:34 -0600)
pod/perlop.pod

index 79e7bd9..9dc9278 100644 (file)
@@ -36,7 +36,8 @@ C<(2 + 4) * 5>. So the expression yields C<2 + 20 == 22>, rather than
 C<6 * 5 == 30>.
 
 I<Operator associativity> defines what happens if a sequence of the same
-operators is used one after another: whether they will be grouped at the left
+operators is used one after another:
+usually that they will be grouped at the left
 or the right. For example, in C<9 - 3 - 2>, subtraction is left associative,
 so C<9 - 3> is grouped together as the left-hand operand of the second
 subtraction, rather than C<3 - 2> being grouped together as the right-hand
@@ -59,6 +60,47 @@ special evaluation rules that can result in an operand not being evaluated at
 all; in general, the top-level operator in an expression has control of
 operand evaluation.
 
+Some comparison operators, as their associativity, I<chain> with others
+of the same precedence.  This means that each comparison is performed
+on the two arguments surrounding it, with each interior argument taking
+part in two comparisons, and the comparison results are implicitly ANDed.
+Thus S<C<"$a E<lt> $b E<lt>= $c">> behaves exactly like S<C<"$a E<lt>
+$b && $b E<lt>= $c">>, assuming that C<"$b"> is as simple a scalar as
+it looks.  The ANDing short-circuits just like C<"&&"> does, stopping
+the sequence of comparisons as soon as one yields false.
+
+In a chained comparison, each argument expression is evaluated at most
+once, even if it takes part in two comparisons.  (It is not evaluated
+at all if the short-circuiting means that it's not required for any
+comparisons.)  This matters if the computation of an interior argument
+is expensive or non-deterministic.  For example,
+
+    if($a < expensive_sub() <= $c) { ...
+
+is not entirely like
+
+    if($a < expensive_sub() && expensive_sub() <= $c) { ...
+
+but instead closer to
+
+    my $tmp = expensive_sub();
+    if($a < $tmp && $tmp <= $c) { ...
+
+in that the subroutine is only called once.  However, it's not exactly
+like this latter code either, because the chained comparison doesn't
+actually involve any temporary variable (named or otherwise): there is
+no assignment.  This doesn't make much difference where the expression
+is a call to an ordinary subroutine, but matters more with an lvalue
+subroutine, or if the argument expression yields some unusual kind of
+scalar by other means.  For example, if the argument expression yields
+a tied scalar, then the expression is evaluated to produce that scalar
+at most once, but the value of that scalar may be fetched up to twice,
+once for each comparison in which it is actually used.
+
+Some operators are instead non-associative, meaning that it is a syntax
+error to use a sequence of those operators of the same precedence.
+For example, S<C<"$a .. $b .. $c">> is an error.
+
 Perl operators have the following associativity and precedence,
 listed from highest precedence to lowest.  Operators borrowed from
 C keep the same precedence relationship with each other, even where
@@ -518,17 +560,8 @@ than or equal to the right argument.
 X<< ge >>
 
 A sequence of relational operators, such as S<C<"$a E<lt> $b E<lt>=
-$c">>, does not group in accordance with left or right associativity,
-which would produce the almost-useless result of using the truth-value
-result of one comparison as a comparand in another comparison.  Instead
-the comparisons are I<chained>: each comparison is performed on the
-two arguments surrounding it, with each interior argument taking part
-in two comparisons, and the comparison results are implicitly ANDed.
-Thus S<C<"$a E<lt> $b E<lt>= $c">> behaves very much like S<C<"$a E<lt>
-$b && $b E<lt>= $c">>.  The ANDing short-circuits just like C<"&&">
-does, stopping the sequence of comparisons as soon as one yields false.
-Each argument expression is evaluated at most once, even if it takes
-part in two comparisons.
+$c">>, performs chained comparisons, in the manner described above in
+the section L</"Operator Precedence and Associativity">.
 
 =head2 Equality Operators
 X<equality> X<equal> X<equals> X<operator, equality>
@@ -550,8 +583,8 @@ to the right argument.
 X<ne>
 
 A sequence of the above equality operators, such as S<C<"$a == $b ==
-$c">>, performs chained comparisons, in the same manner as described in
-the previous section for relational operators.
+$c">>, performs chained comparisons, in the manner described above in
+the section L</"Operator Precedence and Associativity">.
 
 Binary C<< "<=>" >> returns -1, 0, or 1 depending on whether the left
 argument is numerically less than, equal to, or greater than the right