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

Please help me to understand the 'next' command better
For the snippet shown below,
$! = 1; @l_test = (1,2,3,4,5,6,7); foreach $l_rec (@l_test) { next,print '.' if ( 4 == $l_rec); print $l_rec; }
in my opinion the expected output is 123.567
but the actual output is 123567,obviously the print command is getting skipped.
i changed the order in which the next & print is getting called,but the behavior remains consistent
From the documentation I have learnt that :
'Note that a block by itself is semantically identical to a loop that executes once. Thus next will exit such a block early.'
is this the behavior I experience above, please share your thoughts.
Correct my understanding if necessary.

Replies are listed 'Best First'.
Re: understanding next
by GrandFather (Saint) on Jan 31, 2008 at 04:36 UTC

    It's not next that is tripping you up, but the comma operator. The fix that is closest to your original code is:

    use strict; use warnings; $! = 1; my @l_test = (1,2,3,4,5,6,7); foreach my $l_rec (@l_test) { (print '.'), next if ( 4 == $l_rec); print $l_rec; }

    but:

    foreach my $l_rec (@l_test) { if ( 4 == $l_rec) { print '.'; next; }

    would make your intent clearer.

    Update: see Comma Operator


    Perl is environmentally friendly - it saves trees
Re: understanding next
by ysth (Canon) on Jan 31, 2008 at 04:52 UTC
    Since print is a list operator, saying print '.', next if ... is like saying print('.', next) if ..., first calling next and passing it's return value as part of the arguments to print. But next never returns, so the print never happens.

    print('.'), next if ... or (print '.'), next if ... make it work as you intend.

    Hmm, should next in non-void context warn?

Re: understanding next
by wfsp (Abbot) on Jan 31, 2008 at 07:39 UTC
    next/last and the comma can be very useful when used with a flag.

    You want to loop over the whole array and then test if certain conditions were met (and how often).

    my @l_test = (1,2,3,4,5,6,7); my $found; foreach my $l_rec (@l_test) { $found++, next if $l_rec == 4; print $l_rec; } print qq{\nskipped 4\n} if $found;
    You need to detect if a loop exited early.
    my @l_test = (1,2,3,4,5,6,7); my ($found, $bad); foreach my $l_rec (@l_test) { $found++, next if $l_rec == 8; $bad++, last if $l_rec > 10; print $l_rec; } die qq{8 found\n} if $found; die qq{high number found\n} if $bad;
      That's good stuff. I can think of all kinds of places where I can eliminate an "if () {$x++;next}" block and slip in a "$x++, next if" line :)