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

Hi Perl Monks,
I have been trying to develop this simple code of a progress indicator of a twirling baton. The problem is arising from the sleep function which seems to block all print output (even before the sleep statement.) Is this some sort of bug with the sleep function? This is the code that i have:
sub rotate_line { my $interval = 1; # Sleep time between twirls my $tcount = 0; # For each tcount the line twirls one incremen +t while ($interval) { $tcount++; print "$tcount\n"; switch ($tcount) { case 1 { printf '-'; sleep $interval; } case 2 { print "\\"; sleep $interval; } case 3 { print "|"; sleep $interval; } case 4 { print "/"; sleep $interval; } else { $tcount = 0; } } } }
I have been searching for some sort of replacement for the sleep function but have not been successful. Any advice would be greatly appreciated.
Thank you,
Perl noob

Replies are listed 'Best First'.
Re: Twirling baton progress indicator in Perl
by ides (Deacon) on Oct 10, 2005 at 23:20 UTC

    This isn't a problem with sleep so much as a problem with buffered output. Printing a single character isn't filling up your buffer.

    Add this to the top, but inside, your while statement:

    $| = 1;
    This forces a flush right away after every print statement.

    Frank Wiles <frank@wiles.org>
    http://www.wiles.org

      ... and if some spare time is available, probably a look to Suffering from Buffering? by Dominus is a way to spend it well.

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.
Re: Twirling baton progress indicator in Perl
by runrig (Abbot) on Oct 10, 2005 at 23:22 UTC
Re: Twirling baton progress indicator in Perl
by diotalevi (Canon) on Oct 10, 2005 at 23:25 UTC

    I just thought I'd note that there's no switch statement in perl and no one should ever use the Switch module. Its author even tells this to you.

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Twirling baton progress indicator in Perl
by Aristotle (Chancellor) on Oct 11, 2005 at 00:24 UTC

    That seems like a straight translation from C, if the printf still lost in there is any hint. That hypothesis would also explain doing this using a heavily copypasted switch construct, which is a common notion in C culture. But this is Perl, not C, so code smarter, not harder.

    sub rotate_line { my $interval = 1; # Sleep time between twirls my $tcount = 0; # For each tcount the line twirls one incremen +t my @baton = ( '-', '\\', '|', '/' ); while ($interval) { $tcount++; print "$tcount\n"; print $baton[ $tcount % @baton ]; sleep $interval; } }

    (Actually you can trivially do the same thing in C if you use a string to store the baton characters and then address single characters with a bit of pointer math, but I haven’t seen this a lot. C programmers rather like their switches for some reason.)

    Your loop doesn’t terminate either, but it’s obviously only example code so I suppose it doesn’t matter.

    There was also a CPAN module to provide a tied scalar that returns the next character in progression on every read, but its name escapes me and neither search.cpan.org nor Google are any help right now.

    Makeshifts last the longest.

      I know how much we all love when people who haven't been using perl for any length of time bemoan that perl code looks like line noise, or that it's a write-only language. So, I think we should at least not do the same in reverse.

      At no point when I was writing C would I have imagined using either switches or "pointer arithmetic" for this. I would have done basically the same thing you just did, but in C.

      void twirl_baton() { static int position = 0; static char* baton = "-\\|/"; printf("%c\b", baton[position++ % 4]); }
      Which is exactly the same, except it allows work to get accomplished while the baton is twirling, as you just keep calling twirl_baton every so often in the code. Which I'm sure you would have done in perl if it weren't that the OP asked specifically about sleep in their misdiagnosis of their problem. Yes, under the covers, baton[position++ % 4] is pointer arithmetic, but abstractly it is no more pointer arithmetic than your perl usage. For example, array usage is taught way before pointers in most C courses and books.

      That's not to say that some people didn't learn switch statements with the rotating baton - but my experience doesn't show it to be indicative or cause/effect. I would think this to be more indicative of other languages where arrays aren't so easy to do - e.g., REXX or shell. Or languages where many beginners show up, but never advance to the point of seeing/using arrays (I can think of many QBASIC "programmers" falling into this category - I'm sure there are many VB users as well, although with common usage of VB being GUI, Windows Registry, and database interactions, I would think VB would have a lower percentage of these users than previous iterations of BASIC).

        Make no mistake, I’m not complaining about C. I like the language quite a bit, and so long as I don’t have to monkey around on the heap too much it’s a lot of fun. (I also enjoy writing shell scripts and XSLT… :-))

        Yes, under the covers, baton[position++ % 4] is pointer arithmetic, but abstractly it is no more pointer arithmetic than your perl usage.

        Apologies for the bad wording – what I meant to express was that you are addressing particular characters in something that’s not overtly an array. Although now that I think about it, even an honest-to-goodness character array is quite simple so use, you just do something like

        char[] baton = { '-', '\\', '|', '/' }; int num_batons = sizeof( baton ) / sizeof( baton[0] );

        So yeah, I retract that comment. Still, I’ve seen this class of problem very frequently handled with switch in C – and as I now realize, there’s even less reason to do it that way than I thought, even in C.

        Hrm.

        Makeshifts last the longest.

Re: Twirling baton progress indicator in Perl
by GrandFather (Saint) on Oct 10, 2005 at 23:26 UTC

    It works for me and gives the output shown below. (I modified your code slightly so the loop would terminate and to avoid using switch.)

    <readmore title="modified code>
    use strict; use warnings; my $intervals = 20; my $interval = 1; # Sleep time between twirls my $tcount = 0; # For each tcount the line twirls one increment while ($intervals-- > 0) { $tcount++; print "$tcount\n"; if ($tcount == 1) { printf '-'; sleep $interval; } elsif ($tcount == 2) { print "\\"; sleep $interval; } elsif ($tcount == 3) { print "|"; sleep $interval; } elsif ($tcount == 4) { print "/"; sleep $interval; } else { $tcount = 0; } }
    1 -2 \3 |4 /5 1 -2 \3 |4 /5 1 -2 \3 |4 /5 1 -2 \3 |4 /5

    Perl is Huffman encoded by design.