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

Why do these two loops produce different output?

#! perl -slw use strict; print "Loop 1"; A: for my $a ( 0 .. 9 ) { $a % $_ or next A for 2..4; print $a; } print "\nLoop 2"; B: for my $a ( 0 .. 9 ) { for my $b ( 2..4 ) { unless( $a % $b ) { next B; } else { print $a; } } } __END__ C:\test>junk48 Loop 1 1 5 7 Loop 2 1 1 1 3 5 5 5 7 7 7 9

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re: Inverted logic
by SuicideJunkie (Vicar) on Jul 24, 2013 at 15:18 UTC

    A will print at the end of the loop if all of the modulo tests come out true.

    B will print every time one of the modulo tests come out true during the loop.

    What you want is more like:

    print "\nLoop 2"; B: for my $a ( 0 .. 9 ) { for my $b ( 2..4 ) { unless( $a % $b ) { next B; } } print $a; }

      ... I'm getting too slow... ;-)

      I'm pretty sure you updated your answer with the code snippet in a second step, isn't it? :). That would give me some comfort. But anyway: A ++ for being faster...

        Yeah I dropped the explanation first, and then figured it could use a code sample. Failed to check for new posts before submitting; if I'd seen your post I'd have just left mine alone since you said everything I was going to say. Looks like we both made the same code changes at the same time, and ended up with only a 1 character difference :)

        ++ for you too.

Re: Inverted logic
by McA (Priest) on Jul 24, 2013 at 15:21 UTC
    print "\nLoop 3"; B: for my $a ( 0 .. 9 ) { for my $b ( 2..4 ) { unless( $a % $b ) { next B; } } print $a; }

    Best regards
    McA

Re: Inverted logic
by rjt (Curate) on Jul 24, 2013 at 16:38 UTC

    Or, just count by 4s and 2s:

    { my $x; say for map { $x += $_ } 1,(4,2)x($LIM/6) }
    1 5 7 11 13 17 19 . .

    (At least 15x faster than your Grandma's best nested loop, too.)

      Cool 'nall ++, but the real code does somewhat more than just printing a few numbers. (And the numbers aren't constant either.)

      The reason for refactoring is because I now want to do more than just next in that branch of the code.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        What? That was contrived? Next I was going to post say for 1,5,7 and call it a day. :-) I mean... understood. More of a fun reminder to never stop looking for ways to calculate rather than iterate, regardless of the problem.

Re: Inverted logic
by Anonymous Monk on Jul 25, 2013 at 00:43 UTC

    Have you considered a testCondition()? Hmm

    A: for(...){ next A if not my_truthiness( $_ ); print $a; }
    A: for(...){ unless( my_truthiness( $_ ) ){ next A; } print $a; }
    A: for(...){ my_truthiness( $_ ) or next A; print $a; }
    A: for(...){ next A unless my_truthiness( $_ ); print $a; }

      The code I posted contained (a simplified version of) my test condition.

      What good would removing the inner loop do, when it was the inner loop that was the both the heart of the question and the source of the misrefactoring?


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        What good would removing the inner loop do, when it was the inner loop that was the both the heart of the question and the source of the misrefactoring?

        Turning it into a subroutine makes the logic easier to see?