Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Understanding the benefit of Given/When ...

by LanX (Canon)
on Mar 04, 2010 at 14:44 UTC ( #826710=perlquestion: print w/ replies, xml ) Need Help??
LanX has asked for the wisdom of the Perl Monks concerning the following question:

Honorable Monks,

After this discussion -> Re^6: while(){}continue{}; Useful? (Consistent!), I'm trying to understand the extended functionality of the new Given/When compared to the old workaround with For/Next.

As far as I understand,

  • In given/when I have to write a continue (statement not block!) where I omit the next statement. I need to "invert" the fall through.
  • In given/when I lose the continue-block which is always executed.
  • The when has an automatically built in smart match ~~. Nice ...but how can I take profit from this smart match if the parameter passed into given can only be a scalar?

    Maybe I missed something, please see the example code to understand what I mean:

    CODE:

    use feature "switch"; $,=$\="\t"; @test=qw/abc def abcdef nnn/; print "\n\n=== Given/When"; for (@test){ print "\nGIVEN($_):"; given($_) { when (/abc/) { print "abc";continue } when (/def/) { print "def" } when (/xyz/) { print "xyz" } default { print "default" } } } print "\n\n=== For"; for (@test){ for ($_){ print "\nFOR($_):"; if (/abc/) { print "abc"} if (/def/) { print "def" ;next} if (/xyz/) { print "xyz" ;next} print "default"; } } print "\n\n=== For/Continue"; # "simplifying" the former with post-ifs and && # using continue-block my @res; for (@test){ push (@res, "abc") if (/abc/); push (@res, "def") && next if (/def/); push (@res, "xyz") && next if (/xyz/); push (@res, "default"); } continue { print "\nFOR/CONT($_):",@res; @res=(); } print "\n\n === When smartmatch\n"; print "\n= GIVEN(\@test):\n"; given(@test) { print "whats tested is:",$_; when (/abc/) { print "abc";continue } when (/def/) { print "def" } when (/xyz/) { print "xyz" } default { print "default" } } print "\n= GIVEN(\\\@test):\n"; # does when act differently when a arr_reff is passed? given(\@test) { print "whats tested is:",$_; when (/abc/) { print "abc";continue } when (/def/) { print "def" } when (/xyz/) { print "xyz" } default { print "default" } } # whats the point of implicit smartmatch if only scalars can be testet +??? smartmatchingan array is different print "\nBUT: def ~~ \@test!" if @test ~~ /def/;
    OUTPUT:
    === Given/When GIVEN(abc): abc default GIVEN(def): def GIVEN(abcdef): abc def GIVEN(nnn): default === For FOR(abc): abc default FOR(def): def FOR(abcdef): abc def FOR(nnn): default === For/Continue FOR/CONT(abc): abc default FOR/CONT(def): def FOR/CONT(abcdef): abc def FOR/CONT(nnn): default === When smartmatch = GIVEN(@test): whats tested is: ARRAY(0x8a08a38) default = GIVEN(\@test): whats tested is: ARRAY(0x8a08a38) default BUT: def ~~ @test!

    Cheers Rolf

    UPDATE: extended given(Array) and given(Array_ref)

    Since given accepts arrays and automatically passes the ref without when reacting accordingly, I suppose it's a BUG!

  • Comment on Understanding the benefit of Given/When ...
    Select or Download Code
    Re: Understanding the benefit of Given/When ...
    by ikegami (Pope) on Mar 04, 2010 at 15:14 UTC

      The when has an automatically built in smart match ~~. Nice ...but how can I take profit from this smart match if the parameter passed into given can only be a scalar?

      Maybe, but you can check that scalar against a variety of things, not all of them scalars.

      use 5.010; use strict; use warnings; my @x = qw( abc def ); given ("abc") { when (@x) { print "when\n"; } default { print "default\n"; } }

      I have no idea what you are asking.

        > I have no idea what you are asking.

        Maybe I'm not smart enough for Smart Match ;)

        It seems that the operands in Smart Match are swapped to what I expected after reading the docs

        Is perlsyn#Switch statements clear???

        Most of the power comes from implicit smart matching: when($foo) is exactly equivalent to when($_ ~~ $foo)
        ($_ was given)

        and

        # $a $b Type of Match Implied Matching Code # ====== ===== ===================== ============= ... # Array Regex array grep grep /$b/, @$a
        see perlsyn#Smart matching in detail

        so when writing

        given (@a) { when (/abc/) {} }

        I expect this to be tested:  @a ~~ /$b/ in the meaning of  grep /$b/, @$a

        Two possibilities:

        a) the docs need a rewrite!

        b) my brain needs a rewrite! ;)

        Cheers Rolf ...still confused...

        UPDATE: Sorry personally I think that ~~ is far too overloaden with functionality to be easily understood!!!

          I don't know why the following doesn't work:
          use 5.010; use strict; use warnings; my @a='abc'; given (@a) { when (/abc/ ) { print "abc\n" } when (1 ) { print "#\n" } when (['abc']) { print "copy\n" } when (\@a ) { print "self\n" } } # copy
          Why is it skipping Array Regex to go to Array Array?
    Re: Understanding the benefit of Given/When ...
    by JavaFan (Canon) on Mar 04, 2010 at 15:14 UTC
      I don't understand why you think a 'continue-block' is missing from given/when. 'continue-block' is associated with loops; give/when isn't a loop. There's no 'continue-block' for if/elsif/else either. But given that empty blocks are loops, you could write:
      { given ($foo) { when (/bar/) {...} when (/baz/) {...} } } continue { ... always executed ... }
      But I don't see what that buys you over:
      given ($foo) { when (/bar/) {...} when (/baz/) {...} } ... always executed ...
      So, why even want a continue block on given/when? It's not needed, and isn't consistent.
      Nice ...but how can I take profit from this smart match if the parameter passed into given can only be a scalar?
      To give one example:
      my $foo = "bar"; my @foo = qw [foo bar baz]; given ($foo) { when (@foo) {say "Match"} }
      will print Match.
        So, why even want a continue block on given/when? It's not needed, and isn't consistent.

        I see what you mean, maybe I'm still too attached to the concepts of the workaround...(which is easier to understand for me)

        Anyway I think you have a plus because you can use last for leaving without executing the continue block.

        # using continue-block my @res; for (@test){ push (@res, "abc") if (/abc/); push (@res, "def") && last if (/def/); push (@res, "xyz") && next if (/xyz/); push (@res, "default"); } continue { print "\nFOR/CONT($_):",@res; @res=(); }

        OUTPUT:

        === For/Continue FOR/CONT(abc): abc default

        Cheers Rolf

          my @test = qw[abc def ghi xyz]; my @res; for (@test) { when (/abc/) {push @res, "abc"; continue} when (/def/) {push @res, "def"; last} when (/xyz/) {push @res, "xyz"; next} default {push @res, "default"} } continue { print "FOR/CONT($_): @res\n"; @res = (); } __END__ FOR/CONT(abc): abc default

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: perlquestion [id://826710]
    Approved by Corion
    Front-paged by jrsimmon
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others cooling their heels in the Monastery: (15)
    As of 2014-10-30 19:03 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      For retirement, I am banking on:










      Results (208 votes), past polls