Perl 5.14, when it’s released, allows you to use a return value from given-when
. You have to wrap it in a do
(Item 25: Use do {} to create inline subroutines):
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits' } when( /^\p{L}+\z/ ) { 'alphabetics' } when( /^\p{P}+\z/ ) { 'punctuation' } default { 'something else' } } }; say $value;
In this example, you use the \p{...}
to match Unicode properties (Item 76: Match Unicode characters and properties). Here are a couple of sample runs, using Perl 13.5, the development version leading to Perl 5.14 (Item 110: Compile and install your own perl):
$ perl5.13.5 do-given.pl 123 digits $ perl5.13.5 do-given.pl abc alphabetics $ perl5.13.5 do-given.pl .,; punctuation $ perl5.13.5 do-given.pl "|" something else
This has the same advantages as other uses of do
where you can avoid multiple, parallel assignments to the same variable. Prior to Perl 5.14, you would have to do each assignment in each branch, which is quite tedious:
use 5.010; my $value; given ( $ARGV[0] ) { # lots of repeated $var = when( /^\p{N}+\z/ ) { $var = 'digits' } when( /^\p{L}+\z/ ) { $var = 'alphabetics' } when( /^\p{P}+\z/ ) { $var = 'punctuation' } default { $var = 'something else' } } }; say $value;
As with other subroutines and subroutine-like things, the result of the given
is the last evaluated expression. That’s not the same thing as the last expression, or even the last when
block. Remember that you can have interstitial statements too.
Consider the case with some statements after the default block:
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits' } say 'Not digits'; when( /^\p{L}+\z/ ) { 'alphabetics' } say 'Not alphabetics'; when( /^\p{P}+\z/ ) { 'punctuation' } say 'Not punctuation'; default { 'something else' } 'last'; } }; say $value;
No matter what you do, the given
will never return last
because either a when
or the default
block runs.
$ perl5.13.5 do-given.pl "|" Not digits Not alphabetics Not punctuation something else
All blocks have an implicit break
at the end unless you say otherwise:
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits'; break } say 'Not digits'; when( /^\p{L}+\z/ ) { 'alphabetics'; break } say 'Not alphabetics'; when( /^\p{P}+\z/ ) { 'punctuation'; break } say 'Not punctuation'; default { 'something else'; break } 'last'; } }; say $value;
Here’s another case. Without the default
block, you have no guarantee that at least one block will run so you might evaluate that final statement:
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits' } when( /^\p{L}+\z/ ) { 'alphabetics' } when( /^\p{P}+\z/ ) { 'punctuation' } 'last'; } }; say $value;
Now the fall-through cases evaluate that final last
string which becomes the return value:
$ perl5.13.5 do-given.pl "|" last
There’s another case to consider though. What it there is no default block and there are no additional statements after the last when
? What’s the last evaluated expression then? Here’s a when
condition where the value is always false:
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits' } when( /^\p{L}+\z/ ) { 'alphabetics' } when( /^\p{P}+\z/ ) { 'punctuation' } when( 1 == 3 ) { 'always_false' } } }; say "value is defined" if defined $value; say "value is [$value]";
In this case, the return value is both false and undefined, which is just fine:
$ perl5.13.5 do-given.pl value is []
Check out this case, where the last evaluated expression is a true value in the when
condition, but there’s nothing explicit in the block:
use 5.013; my $value = do { given ( $ARGV[0] ) { when( /^\p{N}+\z/ ) { 'digits' } when( /^\p{L}+\z/ ) { 'alphabetics' } when( /^\p{P}+\z/ ) { 'punctuation' } when( 1 == 1 ) { } 'last' } }; say "value is defined" if defined $value; say "value is [$value]";
With no argument, your script should trigger the 1 == 1
condition, which is always true (and also the same as a default
). The return value is undefined here too, even though the last evaluated, explicit expression is true:
$ perl5.13.4 do-given.pl value is []
Not that you should ever have an empty block, but it’s an interesting edge case.
Things to remember
- In Perl 5.14,
given
returns the last evaluated expression but you have to wrap it in ado
to use it. - The last evaluated expression is not necessarily the last expression.
- To try these new features, you need to use the experimental track until that stable version is released.
Why is the “do” necessary? I know it’s probably because perl hasn’t been changed to not need it, but why did they think it was necessary to make people use the “do”? Just seems like extra syntax too me.
I thought the extra do was odd too, but I haven’t bothered to find out why yet. It’s really hard to search perl5-porters for messages with “do” or “given” in them. :)
what about similar constructs, like foreach / for+when / if+elsif+else, will they start magically returning values? if not, why not?
The
foreach
has a return value if you spell itmap
, and you can easily do the same thing withif
and ado
block. Perl 6 has agather
which might do some of this more naturally.