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

Hi Monks I think this question is to do with buffering but I need some pointers because the output is not as I expected.

When I run

$| = 1; my $Qcount = 10; my $Qstart = 0; my $Qint = 3; my @StorageArray; sub incStart { for ( $x = $_[0] ; $x < $_[1] ; $x++ ) { if ( ( $x % $_[2] ) == 0 ) { print $x . "\n"; push (@StorageArray, $x); } } } print "test " . incStart( $Qstart, $Qcount, $Qint ) . "\n";

I expected the output

test0 3 6 9

Instead I get

0 3 6 9 test

I've set the output bufffer to 1 so why dont I get the output I want? There must be something else I dont understand involved. What is it please?

Replies are listed 'Best First'.
Re: Buffering and output help needed
by shmem (Chancellor) on Oct 07, 2006 at 12:22 UTC
    print "test " . incStart( $Qstart, $Qcount, $Qint ) . "\n";
    Prior to the concatenation (the "." operator) incStart() is evaluated. Therefore the print statements in the loop are executed first. Then the concatenation is done ("test " . undef . "\n") and the result ("test \n") handed to print. Last, "test \n" is printed. This has nothing to do with buffering, but with execution order.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Buffering and output help needed
by Joost (Canon) on Oct 07, 2006 at 12:26 UTC
    Take a good look at the last statement:
    print "test " . incStart( $Qstart, $Qcount, $Qint ) . "\n";
    The string to be printed is created by concatenating two string literals with the output of incStart() - that means incStart() needs to run first before the final string to be printed is known. Note that incStart doesn't return anything, it just prints stuff directly. This is seriously ugly :-)

    I suggest you either return the string from incStart instead of printing directly, or you "print 'test '" first and THEN call incStart().

      Thank you, I know it's ugly, so its good that I can come here and get help :)

      Am I better returning values from incStart() pushing them into an array and printing the array?,

      And always seperating the print functions from the calculation functions.

      $| = 1; my $Qcount = 10; my $Qstart = 0; my $Qint = 3; my @StorageArray; sub incStart { for ( $x = $_[0] ; $x < $_[1] ; $x++ ) { if ( ( $x % $_[2] ) == 0 ) { # print $x . "\n"; # push (@StorageArray, $x); return $x; } } } print "test "; print incStart( $Qstart, $Qcount, $Qint ) . "\n";

      This doesnt work either,

        A return() statement exits the subroutine. That means you loop won't be completed, since incStart() will stop and return at the first value that matches ( $x % $_[2] ) == 0.

        You'll want to create a list of matching variables to return. You could do it a bit like this: (code clarified a bit)

        use strict; use warnings; sub incStart { my ($start,$end,$mod) = @_; my @result; for ( my $x = $start ; $x < $end ; $x++ ) { if ( ( $x % $mod ) == 0 ) { push @result,$x; # append $x to result list } } return @result; # <- return AFTER completing the loop } print "test "; foreach my $result (incStart(0,10,3)) { print "$result\n"; }

        Please also be very careful about where you define variables and use strict and warnings.