Section 10.1. Filehandles


10.1. Filehandles

Don't use bareword filehandles.

One of the most efficient ways for Perl programmers to bring misery and suffering upon themselves and their colleagues is to write this:

     open FILE, '<', $filename         or croak "Can't open '$filename': $OS_ERROR";

Using a bareword like that as a filehandle causes Perl to store the corresponding input stream descriptor in the symbol table of the current package. Specifically, the stream descriptor is stored in the symbol table entry whose name is the same as the bareword; in this case, it's *FILE. By using a bareword, the author of the previous code is effectively using a package variable to store the filehandle.

If that symbol has already been used as a filehandle anywhere else in the same package, executing this open statement will close that previous filehandle and replace it with the newly opened one. That's going to be a nasty surprise for any code that was already relying on reading input with <FILE>[*].

[*] Not that we should have too much sympathy for that code, as it's behaving just as badly by using the FILE bareword itself.

The writer of this particular code also chose the imaginative name FILE for this particular filehandle. That's one of the commonest names used for package filehandles[], so the chances of colliding with someone elses open filehandle are greatly enhanced.

[] The other Four Horsemen of the I/O-pocalypse being IN, OUT, FH, and HANDLE.

As if these pitfalls with bareword filehandles weren't bad enough, barewords are even more unreliable if there's a subroutine of the same name currently in scope. And worse still, under those circumstances they may fail silently. For example:

          # Somewhere earlier in the same package (but perhaps in a different file)...     use POSIX;     # and later...     # Open filehandle to the external device...     open EXDEV, '<', $filename         or croak "Can't open '$filename': $OS_ERROR";     # And process data stream...     while (my $next_reading = <EXDEV>) {         process_reading($next_reading);     }

The POSIX module will have quietly exported a subroutine representing the POSIX error-code EXDEV into the package's namespace (just as if that constant had been declared in a use constant pragma). So the open statement is really:

     open EXDEV(  ), '<', $filename         or croak "Can't open '$filename': $OS_ERROR";

When that statement executes, it will first call the EXDEV( ) subroutine, which happens to return the value 18. The open statement then uses that value as a bareword filehandle name, opens an input stream to the requested file, and stores the resulting filehandle in the package's *18 symbol table entry[].

] Yes, its a valid symbol name: the regex capture variable $18 lives there.

Unfortunately, the EXDEV( ) subroutine isn't visible within the angle brackets of a subsequent input operation (i.e., <EXDEV>), because the input operator always treats an enclosed bareword as the direct name of the package filehandle that it's supposed to read from. As a result, the angle brackets attempt to read from *EXDEV, which results in a completely accurate, but highly confusing error message:

     readline(  ) on unopened filehandle EXDEV

The usual conundrum at that point is: how can the filehandle possibly be unopened, when the open statement on the immediately preceding line didn't throw an exception??? And if the obvious culprit (the use POSIX) is off in another file somewhere, it can be very difficult to track down what's going wrong.

Curiously, the code would work as intended if it were rewritten like so:

          # And process data stream...     while (my $next_reading = <18>) {         process_reading($next_reading);     }

But that's hardly an ideal solution. The ideal solution is not to use bareword filehandles at all.



Perl Best Practices
Perl Best Practices
ISBN: 0596001738
EAN: 2147483647
Year: 2004
Pages: 350
Authors: Damian Conway

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net