Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Is there a problem with using barewords as filehandles ?

by syphilis (Bishop)
on Jul 01, 2020 at 09:39 UTC ( #11118753=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

In following the kerfuffle on p5p about the planned release of perl 7, I've noticed a repeated claim that use of barewords as filehandles will be disallowed in perl 7.
What's so wrong with doing open RD, '<', 'file.txt' ?

Is there some official perl documentation about any such issue ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: Is there a problem with using barewords as filehandles ?
by hippo (Chancellor) on Jul 01, 2020 at 09:57 UTC
      > Bareword filehandles are essentially global

      Sorry for nitpicking but they are package variables not full globals.

      Conflicts can be avoided with proper use of package directives.

      Special variables are real globals, they are available everywhere but always belong to main:: package (IIRC)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        Sorry for nitpicking but they are package variables not full globals.

        No need to be sorry! You are quite correct and it's an important distinction. It has been so long since I actually used a user-defined bareword filehandle that I had forgotten that they are indeed package scoped.

        Package variables *are* global (visible everywhere).

      A review of PBP which praises Damian's rationale without quoting it, alas

      If you are really keen you might be able to read at least part of the rationale by searching via google books, I just did that and here is some of Damian's rationale:

      ... using a bareword as a file handle causes Perl to store the corresponding input stream descriptor in the symbol table of the current package ... and if that symbol has already been used as a filehandle anywhere else in the same package, executing this open statement will close the previous file handle and replace it with the newly opened one ... bareword file handles are even more unreliable if there happens to be a subroutine of the same name currently in scope ...

      For completeness, from Perl Best Practices here are all Perl Best Practices that mention bareword or filehandle:

      • 45. Don't use barewords.
      • 125. Don't use bareword filehandles.
      • 126. Use indirect filehandles.
      • 127. If you have to use a package filehandle, localize it first.
      • 130. Close filehandles explicitly, and as soon as possible.
      • 133. Slurp a filehandle with a do block for purity.
      • 136. Always put filehandles in braces within any print statement.
      • 246. Don't tie variables or filehandles.

      As an example, one of my worst debugging sessions involved open's scope. Imagine you have a generic open_file() function in a script. The function uses a bareword FH, because whoever wrote it wasn't thinking about scope, they were just making sure a file was "open" (kinda related to the counterpoint you mentioned, that person might have learned enough to get by but not yet realize all the implications of what they were doing). Sometimes, deep in the code, you might open *another* file while processing the first one, leading to some bewildering action at a distince bugs...
        > because whoever wrote it wasn't thinking about scope,

        FWIW you can localize a FH inside the function's scope, but this implies some glob syntax IIRC.

        I think local *FH but ...

        • I'd need to look it up
        • it'll localize all other vars with the same symbol, like $FH too
        • it's a dynamic runtime scope not a lexical, ie don't call another sub from inside which doesn't localize the same symbol before using it

        Not that beginner friendly

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: Is there a problem with using barewords as filehandles ?
by Discipulus (Abbot) on Jul 01, 2020 at 10:19 UTC
    Hello syphilis,

    I imagine you already know why is better to use lexical filehandles with 3 arguments (enforcing the scope, autoclose,...), but as you are asking about official docs I cannot find anything. Well generally speaking perl documentation is very eterogenous in style. At least.

    > What's so wrong with doing open RD, '<', 'file.txt' ?

    Nothing if you know what happens in this line and in the whole code you are writing.

    perl -we "use strict; open FH, '>', 'text.txt'; open FH, '>', 'text.tx +t';" perl -we "use strict; open my $fh, '>', 'text.txt'; open my $fh, '>', +'text.txt';" "my" variable $fh masks earlier declaration in same scope at -e line 1 +.

    I consider the second line less error prone, if you have thousand lines of code with many open FH statements the risk to forget to close one of them and mess the whole thing is high.

    So it is a matter of (better) habits and nothing wrong per se. See also why-the-modern-perl-book-avoids-bareword-filehandles. And perlmaven.

    More: if it is a matter of good habits I will enforce an exception also in the 2 arguments form of open What happens if you feed open my $in, $filename; with >/etc/passwd ? Infact 2 arguments form is dangeourous.

    If it was my decision I will enhance strict pragma to deal with this:

    use strict; open FH, '<', 'filename'; # dies open my $fh, 'filename'; # dies no strict 'open'; open FH, '<', 'filename'; # now ok open my $fh, 'filename'; # now ok

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Ooh, I do like the idea of a new strict category as a way of enforcing this. Could also work well for traditional prototypes.

Re: Is there a problem with using barewords as filehandles ?
by LanX (Cardinal) on Jul 01, 2020 at 11:04 UTC
    Apart from scoping/namespace rules...

    The essential problem is that subs and FHs can't be distinguished.

    In Perl 4 subs needed a & sigil, this was dropped in Perl 5 but no sigil was introduced for filehandles, so ambiguity was a consequence.

    That's not only frustrating for users but must complicate maintenance of the parser.

    Another problem is passing FH as arguments into subs.

    Then newbies need to learn the whole typeglob technique with *FH.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      >The essential problem is that subs and FHs can't be distinguished.

      This also implies constants defined by constant, which boils down to subroutines.

Re: Is there a problem with using barewords as filehandles ?
by haukex (Bishop) on Jul 01, 2020 at 19:39 UTC
    What's so wrong with doing open RD, '<', 'file.txt' ?

    I was involved with two discussions about this recently, lexical vs. local file handles and Re^2: Summing numbers in a file, so here are my two cents. To summarize the disadvantages of bareword filehandles:

    • They don't protect against typos.
    • They're package-globals.
    • They clash with package names and subs.
    • If you do want to localize them, that comes with even more disadvantages.
    • Package-global filehandles usually go out of scope much later than lexicals, so the automatic close doesn't really help.

    I don't think that bareword filehandles should "never, ever" be used, and removing them would most likely break a lot of CPAN. But IMHO they shouldn't be used in new code, and newcomers should use lexicals instead. My understanding of Perl 7 is that it is an attempt to introduce defaults that are modern and reduce the cognitive load on the coder - sure, you can use bareword filehandles if you know what you're doing and are willing to manually check for all potentially typos and name clashes caused by them. In the beginning, I used to code without strict and warnings, and I can still remember the amount of time I would spend proofreading my code for such issues.

    use of barewords as filehandles will be disallowed in perl 7

    My understanding of Sawyer's talk is that the new default will be no bareword::filehandles, and you are free to write use bareword::filehandles.

      .... you are free to write use bareword::filehandles

      Thanks for pointing that out.

      And thanks to everyone for all the additional relevant points and information.

      I don't do much with perl filehandles, but when I do, I've generally used barewords.
      I thought I would have made every dumb mistake that was possible with them, but I can see there are some mistakes that I hadn't encountered.
      (I wonder if that implies that I'm actually smarter than I thought ;-)

      Cheers,
      Rob
Re: Is there a problem with using barewords as filehandles ? (updated link)
by LanX (Cardinal) on Jul 01, 2020 at 10:17 UTC
Re: Is there a problem with using barewords as filehandles ?
by eyepopslikeamosquito (Bishop) on Jul 02, 2020 at 09:55 UTC

    For completeness, good ol' merlyn's classic Perl Best Practices slideshare:

    • 10.1 Filehandles (slide 136)
    • 10.2 Indirect Filehandles (slide 137)
    • 10.3 Localizing Filehandles (slide 138)
    • 10.4 Opening Cleanly (slide 139)

    gives some excellent advice:

    • Don't use bareword filehandles: can't easily pass them around; can't easily localize them; can't make them "go out of scope".
    • Use indirect filehandles: they close automatically; can be passed to/from subroutines; can be stored in aggregates; might need readline or print {  } though - e.g. my $line = readline $inputs[3]; print { $output_for{$day} } @list;
    • Localizing filehandles: if you must use a package filehandle localize it; local *HANDLE; beware this also stomps on other package items ... so use it sparingly ... that's why indirect handles are better.
    • Opening cleanly: use IO::File or 3-arg open.

Re: Is there a problem with using barewords as filehandles ?
by jcb (Priest) on Jul 02, 2020 at 03:49 UTC

    Bareword filehandles have their places, particularly in simple scripts, where there really is almost no difference between them and lexical file handles — declaring a lexical at file-scope has almost exactly the same effect, and exactly the same effect if the convention of maintaining a 1:1 mapping between files and packages is followed.

    However, a sub that opens a file and returns a handle should always return a lexical filehandle, unless its purpose is to return "THE" singleton filehandle for some resource, and in that case it should be using our to store the filehandle in a global. Generally, bareword filehandles should be limited to the mainline code in the top-level script. Subroutines should use lexical filehandles and modules should only contain subroutines.

    In Perl, all "globals" are actually package variables, although a few special names (including the "punctuation variables") are forced into package main. The distinction is that a "global" variable is stored in a symbol table slot in some package. Package variables in Perl are globally-accessible, since the package namespace is itself global. The our keyword creates lexically-scoped aliases to package variables and is very convenient when needed.

    A lexical declared at file scope is effectively a global variable and has all of the same problems in complex code, with the additional risk that file-scope lexicals can be shared across packages if multiple packages are defined in the same file. Global variables are generally dangerous in programming and I strongly favor the use of bareword filehandles at top-level in preference to declaring lexicals at file-scope and thinking that you are safe.

    Perhaps the best would be to default to use bareword::filehandles in package main and no bareword::filehandles in other packages. This keeps the feature where it is most useful, to avoid the "head in sand" problem of using file-scope lexicals in the main script, while still pushing modules to avoid the feature unless it really is appropriate.

      I strongly favor the use of bareword filehandles at top-level in preference to declaring lexicals at file-scope and thinking that you are safe.

      the "head in sand" problem

      "driving isnt safe anyway so dont wear a seatbelt, that'll make you drive more careful"

        No, more like "do not act like that fancy sash you are wearing is a seatbelt" — lexicals declared at file-scope are global variables and acting like they are somehow different is sticking your head in the sand.

Re: Is there a problem with using barewords as filehandles ?
by syphilis (Bishop) on Jul 18, 2020 at 04:03 UTC
    use of barewords as filehandles will be disallowed in perl 7

    Just a couple of additional questions:
    When (if) bareword filehandles are disallowed, will we still be able to do:
    print STDERR 'ok';
    I thought this might have been touched on elsewhere in this thread, but I can't see it now. (Apologies if I've missed it.)
    Also, if foo() is an XSub that takes a FILE* as its first argument, would I still be allowed to call it from perl with:
    foo(*STDOUT, ....);
    Maybe I should just wait and see what happens ?

    Cheers,
    Rob
      When (if) bareword filehandles are disallowed, will we still be able to do: print STDERR 'ok';

      If bareword::filehandles is anything to go by, then STDIN, STDOUT, STDERR, ARGV, ARGVOUT, and DATA would still be allowed.

        If bareword::filehandles is anything to go by ....

        Aaah, yes - I'll take my cues from bareword::filehandles. Seems likely (even if not actually guaranteed) that this would be something we "can go by".
        So far, so good - the changes I've made are working ok under use bareword::filehandles;
        Thanks haukex.

        Cheers,
        Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11118753]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2020-08-09 11:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which rocket would you take to Mars?










    Results (54 votes). Check out past polls.

    Notices?