diff options
author | Zefram <zefram@fysh.org> | 2017-11-21 18:17:10 +0000 |
---|---|---|
committer | Zefram <zefram@fysh.org> | 2017-11-21 18:17:10 +0000 |
commit | b69ef0135bfebf0c32023bcb970dbb95957b32e7 (patch) | |
tree | 30b3226764fe880873e9d64bbb41200cc7aa5dd5 /pod/perlsyn.pod | |
parent | 76ed45178844dff782880573017d9b7c9fbc0007 (diff) | |
download | perl-b69ef0135bfebf0c32023bcb970dbb95957b32e7.tar.gz |
regularise "when"
Remove from "when" the implicit enreferencement of array/hash conditions
and the implicit smartmatch of most conditions. Delete most of the
documentation about behaviour of older versions of given/when, because
explaining the now-old "when" behaviour would be excessively cumbersome
and there's little compatibility to take advantage of. Delete the
documentation about differences of given/when from the Perl 6 feature,
because the differences are now even more extensive and it's too much
difference to sensibly explain. Add tests of "when" in isolation.
Diffstat (limited to 'pod/perlsyn.pod')
-rw-r--r-- | pod/perlsyn.pod | 275 |
1 files changed, 12 insertions, 263 deletions
diff --git a/pod/perlsyn.pod b/pod/perlsyn.pod index 80eca0a275..d02516cab4 100644 --- a/pod/perlsyn.pod +++ b/pod/perlsyn.pod @@ -671,29 +671,18 @@ Or if you don't care to play it safe, like this: default { $nothing = 1 } } -The arguments to C<given> and C<when> are in scalar context, -and C<given> aliases the C<$_> variable to the result of evaluating its +The arguments to C<given> and C<when> are in scalar context. +C<given> aliases the C<$_> variable to the result of evaluating its topic expression. +C<when> evaluates its argument as a truth value. If the argument +was false then it does not execute its block, and proceeds to the +following statement. If the argument was true, it executes the block, +then implicitly jumps to the end of the topicalizer. -Exactly what the I<EXPR> argument to C<when> does is hard to describe -precisely, but in general, it tries to guess what you want done. Sometimes -it is interpreted as C<< $_ ~~ I<EXPR> >>, and sometimes it is not. It -also behaves differently when lexically enclosed by a C<given> block than -it does when dynamically enclosed by a C<foreach> loop. The rules are far -too difficult to understand to be described here. See L</"Experimental Details -on given and when"> later on. - -Due to an unfortunate bug in how C<given> was implemented between Perl 5.10 -and 5.16, under those implementations the version of C<$_> governed by -C<given> is merely a lexically scoped copy of the original, not a -dynamically scoped alias to the original, as it would be if it were a -C<foreach> or under both the original and the current Perl 6 language -specification. This bug was fixed in Perl 5.18 (and lexicalized C<$_> itself -was removed in Perl 5.24). - -If your code still needs to run on older versions, -stick to C<foreach> for your topicalizer and -you will be less unhappy. +On versions of Perl preceding Perl 5.28, C<given> and C<when> behave +somewhat differently from their present behaviour. +If your code needs to run on older versions, +avoid C<given> and C<when>. =head2 Goto X<goto> @@ -907,194 +896,10 @@ shell: =head2 Experimental Details on given and when As previously mentioned, the "switch" feature is considered highly -experimental; it is subject to change with little notice. In particular, -C<when> has tricky behaviours that are expected to change to become less -tricky in the future. Do not rely upon its current (mis)implementation. -Before Perl 5.28, C<given> also had tricky behaviours that you should still +experimental; it is subject to change with little notice. +Before Perl 5.28, C<given> and C<when> had tricky behaviours that you should beware of if your code must run on older versions of Perl. -Here is a longer example of C<given>: - - use feature ":5.10"; - given ($foo) { - when (undef) { - say '$foo is undefined'; - } - when ("foo") { - say '$foo is the string "foo"'; - } - when ([1,3,5,7,9]) { - say '$foo is an odd digit'; - continue; # Fall through - } - when ($_ < 100) { - say '$foo is numerically less than 100'; - } - when (\&complicated_check) { - say 'a complicated check for $foo is true'; - } - default { - die q(I don't know what to do with $foo); - } - } - -Before Perl 5.18, C<given(EXPR)> assigned the value of I<EXPR> to -merely a lexically scoped I<B<copy>> (!) of C<$_>, not a dynamically -scoped alias the way C<foreach> does. That made it similar to - - do { my $_ = EXPR; ... } - -except that the block was automatically broken out of by a successful -C<when> or an explicit C<break>. Because it was only a copy, and because -it was only lexically scoped, not dynamically scoped, you could not do the -things with it that you are used to in a C<foreach> loop. In particular, -it did not work for arbitrary function calls if those functions might try -to access $_. Best stick to C<foreach> for that. - -Before Perl 5.28, if the I<EXPR> in C<given(EXPR)> was an array or hash -reference then the topic would be a reference to that array or hash, -rather than the result of evaluating the array or hash in scalar context. - -Most of the power comes from the implicit smartmatching that can -sometimes apply. Most of the time, C<when(EXPR)> is treated as an -implicit smartmatch of C<$_>, that is, C<$_ ~~ EXPR>. (See -L<perlop/"Smartmatch Operator"> for more information on smartmatching.) -But when I<EXPR> is one of the 10 exceptional cases (or things like them) -listed below, it is used directly as a boolean. - -=over 4 - -=item Z<>1. - -A user-defined subroutine call or a method invocation. - -=item Z<>2. - -A regular expression match in the form of C</REGEX/>, C<$foo =~ /REGEX/>, -or C<$foo =~ EXPR>. Also, a negated regular expression match in -the form C<!/REGEX/>, C<$foo !~ /REGEX/>, or C<$foo !~ EXPR>. - -=item Z<>3. - -A smart match that uses an explicit C<~~> operator, such as C<EXPR ~~ EXPR>. - -B<NOTE:> You will often have to use C<$c ~~ $_> because the default case -uses C<$_ ~~ $c> , which is frequentlythe opposite of what you want. - -=item Z<>4. - -A boolean comparison operator such as C<$_ E<lt> 10> or C<$x eq "abc">. The -relational operators that this applies to are the six numeric comparisons -(C<< < >>, C<< > >>, C<< <= >>, C<< >= >>, C<< == >>, and C<< != >>), and -the six string comparisons (C<lt>, C<gt>, C<le>, C<ge>, C<eq>, and C<ne>). - -=item Z<>5. - -At least the three builtin functions C<defined(...)>, C<exists(...)>, and -C<eof(...)>. We might someday add more of these later if we think of them. - -=item Z<>6. - -A negated expression, whether C<!(EXPR)> or C<not(EXPR)>, or a logical -exclusive-or, C<(EXPR1) xor (EXPR2)>. The bitwise versions (C<~> and C<^>) -are not included. - -=item Z<>7. - -A filetest operator, with exactly 4 exceptions: C<-s>, C<-M>, C<-A>, and -C<-C>, as these return numerical values, not boolean ones. The C<-z> -filetest operator is not included in the exception list. - -=item Z<>8. - -The C<..> and C<...> flip-flop operators. Note that the C<...> flip-flop -operator is completely different from the C<...> elliptical statement -just described. - -=back - -In those 8 cases above, the value of EXPR is used directly as a boolean, so -no smartmatching is done. You may think of C<when> as a smartsmartmatch. - -Furthermore, Perl inspects the operands of logical operators to -decide whether to use smartmatching for each one by applying the -above test to the operands: - -=over 4 - -=item Z<>9. - -If EXPR is C<EXPR1 && EXPR2> or C<EXPR1 and EXPR2>, the test is applied -I<recursively> to both EXPR1 and EXPR2. -Only if I<both> operands also pass the -test, I<recursively>, will the expression be treated as boolean. Otherwise, -smartmatching is used. - -=item Z<>10. - -If EXPR is C<EXPR1 || EXPR2>, C<EXPR1 // EXPR2>, or C<EXPR1 or EXPR2>, the -test is applied I<recursively> to EXPR1 only (which might itself be a -higher-precedence AND operator, for example, and thus subject to the -previous rule), not to EXPR2. If EXPR1 is to use smartmatching, then EXPR2 -also does so, no matter what EXPR2 contains. But if EXPR2 does not get to -use smartmatching, then the second argument will not be either. This is -quite different from the C<&&> case just described, so be careful. - -=back - -These rules are complicated, but the goal is for them to do what you want -(even if you don't quite understand why they are doing it). For example: - - when (/^\d+$/ && $_ < 75) { ... } - -will be treated as a boolean match because the rules say both -a regex match and an explicit test on C<$_> will be treated -as boolean. - -Also: - - when ([qw(foo bar)] && /baz/) { ... } - -will use smartmatching because only I<one> of the operands is a boolean: -the other uses smartmatching, and that wins. - -Further: - - when ([qw(foo bar)] || /^baz/) { ... } - -will use smart matching (only the first operand is considered), whereas - - when (/^baz/ || [qw(foo bar)]) { ... } - -will test only the regex, which causes both operands to be -treated as boolean. Watch out for this one, then, because an -arrayref is always a true value, which makes it effectively -redundant. Not a good idea. - -Tautologous boolean operators are still going to be optimized -away. Don't be tempted to write - - when ("foo" or "bar") { ... } - -This will optimize down to C<"foo">, so C<"bar"> will never be considered (even -though the rules say to use a smartmatch -on C<"foo">). For an alternation like -this, an array ref will work, because this will instigate smartmatching: - - when ([qw(foo bar)] { ... } - -This is somewhat equivalent to the C-style switch statement's fallthrough -functionality (not to be confused with I<Perl's> fallthrough -functionality--see below), wherein the same block is used for several -C<case> statements. - -Another useful shortcut is that, if you use a literal array or hash as the -argument to C<given>, it is turned into a reference. So C<given(@foo)> is -the same as C<given(\@foo)>, for example. - -C<default> behaves exactly like C<when(1 == 1)>, which is -to say that it always matches. - =head3 Breaking out You can use the C<break> keyword to break out of the enclosing @@ -1183,60 +988,4 @@ interested in only the first match alone. This doesn't work if you explicitly specify a loop variable, as in C<for $item (@array)>. You have to use the default variable C<$_>. -=head3 Differences from Perl 6 - -The Perl 5 smartmatch and C<given>/C<when> constructs are not compatible -with their Perl 6 analogues. The most visible difference and least -important difference is that, in Perl 5, parentheses are required around -the argument to C<given()> and C<when()> (except when this last one is used -as a statement modifier). Parentheses in Perl 6 are always optional in a -control construct such as C<if()>, C<while()>, or C<when()>; they can't be -made optional in Perl 5 without a great deal of potential confusion, -because Perl 5 would parse the expression - - given $foo { - ... - } - -as though the argument to C<given> were an element of the hash -C<%foo>, interpreting the braces as hash-element syntax. - -However, their are many, many other differences. For example, -this works in Perl 5: - - use v5.12; - my @primary = ("red", "blue", "green"); - - if (@primary ~~ "red") { - say "primary smartmatches red"; - } - - if ("red" ~~ @primary) { - say "red smartmatches primary"; - } - - say "that's all, folks!"; - -But it doesn't work at all in Perl 6. Instead, you should -use the (parallelizable) C<any> operator: - - if any(@primary) eq "red" { - say "primary smartmatches red"; - } - - if "red" eq any(@primary) { - say "red smartmatches primary"; - } - -The table of smartmatches in L<perlop/"Smartmatch Operator"> is not -identical to that proposed by the Perl 6 specification, mainly due to -differences between Perl 6's and Perl 5's data models, but also because -the Perl 6 spec has changed since Perl 5 rushed into early adoption. - -In Perl 6, C<when()> will always do an implicit smartmatch with its -argument, while in Perl 5 it is convenient (albeit potentially confusing) to -suppress this implicit smartmatch in various rather loosely-defined -situations, as roughly outlined above. (The difference is largely because -Perl 5 does not have, even internally, a boolean type.) - =cut |