http://www.perlmonks.org?node_id=1043439

mrguy123 has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks, say I want to compare a number to several ranges using given. I think in Perl6 it's supposed to look like this:
given( $x ){ when 2..5 { } when 6..10 { } default{ } }
Any idea how to do it in 5.10?
Thanks, Mister Guy

Solved -thanks for the help. Am now trying to discover how "safe" using given/when is (as of Perl 5.18, given/when has been marked experimental and issues warnings because it may undergo major changes in a future version of Perl)

Replies are listed 'Best First'.
Re: range comparison in given
by tobyink (Canon) on Jul 10, 2013 at 10:40 UTC

    given( $x ){ when ([2..5]) { ...; } when ([6..10]) { ...; } default { ...; } }

    Bear in mind that as of Perl 5.18, given/when has been marked experimental (and issues warnings) because it may undergo major changes in a future version of Perl.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
      Thanks for the tip, works perfectly!
      How much should I worry about given/when?
      I still have bad memories from Perl's switch

        when is considered to be particularly confusing, as it does two different things:

        when ("foo") {...} # means: if ($_ ~~ "foo") when ( constant() ) {...} # means: if ($_ ~~ constant()) when ( somefunc() ) {...} # means: if (somefunc())

        The rules for determining when there's an implicit "$_ ~~" in front of the condition usually do what you mean, but are very convoluted, so it's easy to shoot yourself in the foot.

        given has already changed in Perl 5.18 to use our $_ instead of my $_ (unless there's already a my $_ in the current lexical scope).

        Smart match itself is likely to undergo some simplification. If you take a look at "Smartmatch operator" in perlop, you'll see basically a dispatch table of all the different types of matches it can attempt. This is likely to be cut down to just a handful.

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
        Be afraid; be very afraid! ... unless you're writing one-offs that will never be used again nor ever be used with a later version of Perl.

        If you didn't program your executable by toggling in binary, it wasn't really programming!

Re: range comparison in given
by Lotus1 (Vicar) on Jul 10, 2013 at 14:21 UTC

    Update: Removed the unneeded nested foreach loop.

    You can use foreach in place of given without the weird side effects. I adapted the following from an example at brian d. foy's blog about given/when.

    use v5.10; use warnings; foreach ( 'a', 'z', 5..11 ) { when( /a/ ) { say "$_ : ", 'Matched an a' } when( [ 2..5 ] ) { say "$_ : Matched 2 through 5" } #line 7 when( [ 6..10 ] ) { say "$_ : Matched 6 through 10" } default { say "$_ : Matched nothing" } }
    a : Matched an a Argument "z" isn't numeric in smart match at C:\b\perlmonks\switch.pl +line 7. z : Matched nothing 5 : Matched 2 through 5 6 : Matched 6 through 10 7 : Matched 6 through 10 8 : Matched 6 through 10 9 : Matched 6 through 10 10 : Matched 6 through 10 11 : Matched nothing
Re: range comparison in given
by kcott (Archbishop) on Jul 11, 2013 at 07:53 UTC

    G'day mrguy123,

    "Solved -thanks for the help. Am now trying to discover how "safe" using given/when is (as of Perl 5.18, given/when has been marked experimental and issues warnings because it may undergo major changes in a future version of Perl)"

    You can avoid the (experimental) given/when/.../default construct by using a (non-experimental) for/if/elsif/.../else construct. Here's an example for your specific range comparison:

    $ perl -Mstrict -Mwarnings -E ' my $re_2_5 = qr{^@{[join "|", 2 .. 5]}$}; my $re_6_10 = qr{^@{[join "|", 6 .. 10]}$}; for my $x (4 .. 7, 11) { for ($x) { if (/$re_2_5/) { say "$_ in 2-5 range" } elsif (/$re_6_10/) { say "$_ in 6-10 range" } else { say "$_ not in range" } } } ' 4 in 2-5 range 5 in 2-5 range 6 in 6-10 range 7 in 6-10 range 11 not in range

    There's lots of other ways to achieve this. Here's one using nested ternary operators:

    $ perl -Mstrict -Mwarnings -E ' my $re_2_5 = qr{^@{[join "|", 2 .. 5]}$}; my $re_6_10 = qr{^@{[join "|", 6 .. 10]}$}; for my $x (4 .. 7, 11) { for ($x) { say /$re_2_5/ ? "$_ in 2-5 range" : /$re_6_10/ ? "$_ in 6-10 range" : "$_ not in range" } } ' 4 in 2-5 range 5 in 2-5 range 6 in 6-10 range 7 in 6-10 range 11 not in range

    See also perlsyn - Basic BLOCKs which has other alternatives.

    -- Ken