Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Perl Idioms Explained - $|++

by broquaint (Abbot)
on Aug 01, 2003 at 16:05 UTC ( [id://280025]=perlmeditation: print w/replies, xml ) Need Help??

"Perl Idioms Explained" explained

This is the first post in a series of posts that aim to explain the workings and reasoning behind common perl idioms. Each post will be relatively short but hopefully informative enough to sufficiently illuminate each idiom.

Perl Idioms Explained - $|++

use strict; use warnings; $|++; use Some::Module 'process_stuff'; print '.' while process_stuff();
It is not entirely uncommon to see this rather mysterious combination of characters following the usual pragma declarations - $|++. The most perfunctory glance will reveal that the post-increment operator is used, and a further look will show that said operator is working on the $|. Browsing through man perlvar we see that $| is defined like so

autoflush HANDLE EXPR
$OUTPUT_AUTOFLUSH
$|

If set to nonzero, forces a flush right away and after every write or print on the currently selected output channel. Default is 0 (regardless of whether the channel is really buffered by the system or not; "$|" tells you only whether you've asked Perl explicitly to flush after each write). STDOUT will typically be line buffered if output is to the terminal and block buffered otherwise. Setting this variable is useful primarily when you are outputting to a pipe or socket, such as when you are running a Perl program under rsh and want to see the output as it's happening. This has no effect on input buffering. See the getc entry in the perlfunc manpage for that. (Mnemonic: when you want your pipes to be piping hot.)

So the the post-increment on the $| sets it to 1 (sidenote - its value, magically, can only ever be 0 or 1) which will turn off buffering for STDOUT. The implications for turning off buffering are far reaching so if you'd like to know more about it then see Dominus' cracking Suffering from Buffering. For a simple demonstration of this idiom in action and the effects of output buffering try running the following piece of code

print "printing dots with buffering\n"; select undef, undef, undef, 0.25 or print '.' for 1 .. 10; print "\nflush forced\n"; $|++; print "printing dots without buffering\n"; select undef, undef, undef, 0.25 or print '.' for 1 .. 10; print "\nflush forced\n";
When that is run you should notice that with buffering the dots aren't displayed until the flush is forced with a \n, whereas without buffering the dots were displayed immediately as the output wasn't being held in an output buffer.

Summary

The $|++ idiom will turn buffering off for when we want to see our output, and we want to see it now!

_________
broquaint

Replies are listed 'Best First'.
Re: Poor Perl Idioms Explained (except not really)
by diotalevi (Canon) on Aug 01, 2003 at 16:40 UTC

    This is a pet peeve of mine. I really, really dislike it when people use decrement or increment on $|. If $| is already zero then decrementing it doesn't cause it to remain false, it becomes true. Ugh! I think that by using increment on $| you imply that decrement would also be sane. It isn't and the only sane way to cause $| to be false is through an assignment. Arithmetic on $| is hooey.

    Added note: you're supposed to say $| = 1 and $| = 0. At least then you know what the value of $| will be.

    $ perl -le 'for(0..4){print $|--}' 0 1 0 1 0 $ perl -le 'for(0..4){print $|++}' 0 1 1 1 1
      I completely agree. $|++ gives the erroneous impression that you can somehow have nested $| setting, and I've seen people bitten by this when they think that they're still set to autoflush (because of nested increments) when they aren't. It's a bad idiom, and I'm half-tempted to make $| roll over and toggle state in perl 6. (Which I know won't happen, which is fine, the same way that perl 6 won't deliver 20kV across the keyboard of anyone who writes code like $foo ? bax($bar) ? 12 : xyzzy(34) : $x or $y ? foo() : bar() though I can but dream)
      An old manager of mine saw $|++ in some of my code and requested i change it to $| = 1. I asked why and he replied that it's better to explicitly set something than to assume it is, say, zero. I know that $| defaults to 0, you know that $| defaults to 0 ... but what if someday the default for $| is instead 1?

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
        what if someday the default for $| is instead 1?
        That's not the problem:
        $ perl -le '$| = 1; $|++; print $|++' 1
        The problem is that it might confuse someone who doesn't know about this particular piece of DWIMmery.

        Update: removed unfunny joke

Re: Perl Idioms Explained - $|++
by chromatic (Archbishop) on Aug 01, 2003 at 18:30 UTC
    The $|++ idiom will turn buffering off for when we want to see our output, and we want to see it now!

    ... thus giving the illusion of better performance at the expense of better performance.

    Sometimes that's necessary. I see a lot of programs that disable buffering out of habit where it's unnecessary. Buffering's done for a reason — if you really don't need it, that's one thing, but I think it's silly to disable good things.

Re: Perl Idioms Explained - $|++
by bsb (Priest) on Aug 02, 2003 at 06:05 UTC
    Each post will be relatively short but hopefully informative enough to sufficiently illuminate each idiom.

    For the rest of the series, I'd prefer it if the summary came first.
    Everything else is more of a FMTYEWTK about a 4 character idiom.

    Brad

    --
    ... There is dignity in paucity of words. ... -- Hagakure

Re: Perl Idioms Explained - $|++
by NetWallah (Canon) on Aug 01, 2003 at 19:21 UTC
    Absolutely agree with the peeve.

    I would like to see this coded like this:

    use strict; use warnings; use constant {OUTPUT_AUTOFLUSH_BUFFERED =>0, OUTPUT_AUTOFLUSH_UNBUFFERED=>1}; $| = OUTPUT_AUTOFLUSH_UNBUFFERED; ...
    This makes the meaning MUCH clearer.
      I would like to see this coded like this:

      Ugh. I wouldn't. First, we don't need Yet-Another-Pair-Of-Constants-For-Zero-And-One. Really, most of us are pretty comfortable with the fact that 0 means 'false', 'no', or 'off' and that 1 means 'true', 'yes', or 'on' depending on context. Defining more aliases for every place where a zero or one will do is just false hubris.

      Constants are good for two things. They are good when they can be used to replace a long or difficult-to-remember literal value. Something like use constant PI => 3.14159265358979; would fit in this category of use. The other time to use constants, as unintuitive as it seems, is when they might need to change. That is, when they might need to change between platforms, installations, or even executions but they need to remain constant throughout any single execution. Constants named things like MAXINT, INSTALL_BASE, and DEBUG probably fall in this category. Of course, the two categories aren't mutually exclusive. The LOCK_* constants provided by Fcntl might be an example of some that are good for both reasons.

      This makes the meaning MUCH clearer.

      Again, I disagree. It doesn't make the meaning clearer at all. The uninitiated user will still wonder what that $| variable is. That is the point that needs to be clarified not that a 1 means on and a 0 means off. Of course, you can make it clear with the line use English; which will provide you with the nicely named $OUTPUT_AUTOFLUSH alias.

      Just the same, I'm completely comfortable with idiomatic perl and I don't use the English module. (If someone maintaining my code isn't already familiar with most special variables and doesn't at least know how to look them up in perlvar, then they're probably in over their heads anyway.) I use $| = 1; with abandon in smaller scripts¹.

      Besides, even a nice alias for the admittedly esoteric $| doesn't address the larger problem that no one has yet mentioned. That is, $| is associated with the currently selected filehandle. Keeping track of that can be difficult. In larger scripts, I simultaneously handle that and the clarity issue by writing code like this

      use IO::Handle; STDOUT->autoflush;

      1. And yes, I'm guilty of using $|++ as well despite the fact that I agree it has drawbacks.

      -sauoq
      "My two cents aren't worth a dime.";
      

        In larger scripts, I simultaneously handle that and the clarity issue by writing code like this
        001 use IO::Handle; 002 STDOUT->autoflush;

        I got kinda turned off of IO->Handle when I read this comment in the pod

        use IO::Handle; # thousands of lines just for autoflush :-(

        When I read the authors name, it strengthened the feeling.

        Update: To clarify, the author to which I referred was the author of the comment I quoted above--from the pod of perlipc not IO->Handle--Tom Christiansen, who comments are to be valued.

        I have absolutely nothing against Graham Barr (the author of IO::Handle), nor even much against that module.

        My only reservation was of the practice of using IO->Handle only for the purposes of turning on autoflush.

        If $|=1; $|=0; is deemed to cryptic, you could use something like:

        sub autoflush (*$) { # Set the state of autoflush for # the handle supplied as $_[0] # to the boolean state supplied as $_[1] select( do{ my $old = select( $_[0] ); $| = $_[1]; $old; } ) } ... autoflush( STDOUT, 1 ); # autoflush on ... autoflush( STDOUT, 0 ); # autoflush off

        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.

        First, we don't need Yet-Another-Pair-Of-Constants-For-Zero-And-One.

        I've come across cases where it helps readability. Specifically, when there are many cases where some arguments to the same function are actually interpreted as numbers and some others are booleans, then it can be much more maintainable to see something like $button->set_border(TRUE, 0, 2.5);, which clarifies that the 0 was meant as an actual numerical value of zero.

        I've never had a case where I wanted any more named constants than for TRUE and FALSE, though.

        Makeshifts last the longest.

      Well if you're going that far, you might as well use English; and use $OUTPUT_AUTOFLUSH too.
      How about using a comment instead?

      $|=1; # autoflush

Re: Perl Idioms Explained - $|++
by NetWallah (Canon) on Aug 01, 2003 at 23:17 UTC
    Re: sauoq's comment:First, we don't need Yet-Another-Pair-Of-Constants-For-Zero-And-One.

    I agree that it is ugly to have to declare those constants - If I had my way, they would be easily import-able, probably with use English;; but I do think it makes the code more readable/maintainable.

    The objective is to allow moderately knowledgible perl-ites to be able to read the code, and be fairly confident that they understand it, without having to refer to a manual.

    In this case, even using the name "$OUTPUT_AUTOFLUSH=1" does not clue the reader that his output is now UNBUFFERED. Hence, even with use English; (which is a good idea), I would still use the constants.

      If they don't know that "AUTOFLUSH" flushes the output automatically, they probably don't know what the heck "UNBUFFERED" means.

      (And the converse -- if they have any clue what flushing is at all, they probably know what "AUTOFLUSH" means.)

        Can you tell me if I need to specify the $|++ (or equivalent) in "ALL" perl scripts within a process; or only the main driver. I have about 50 perl scripts several layers deep (i.e. "A" invokes "B" which invokes "C" and "D" and "E" etc.....) By the way I have tried it in a few scripts with no luck yet ... the output to my screen still only displays every 50 lines or so. Are they any gotcha's? Thanks Wayne
Re: Perl Idioms Explained - $|++
by PSP (Initiate) on Aug 03, 2017 at 06:45 UTC

    Thanks for sharing perl knowledge broquaint and helping community. Could you please explain "select undef, undef, undef, 0.25" in details.

      See select, the select RBITS,WBITS,EBITS,TIMEOUT section, which shows the very line as an example. It's cleaner to use
      use Time::Hires qw{ sleep }; sleep 0.25;
      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://280025]
Approved by adrianh
Front-paged by LAI
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-03-19 06:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found