Three-arg open() (Migrating to Modern Perl)


I can forgive novices for writing clunky Perl code because they're following the example of far too many books and tutorials. If you date the Perl Renaissance to the year 2000 (as I do), then you can identify code written before that point and code written after that point.

If modern Perl is safer or easier or clearer or simpler or cleaner to write than legacy Perl, then it should be possible to explain how and why to use modern features in lieu of older features.

For example....

Three-argument open()

There are two forms of the open() function in Perl 5. The modern version takes three arguments: the filehandle to open or vivify, the mode of the filehandle, and the name of the file.

The legacy version has two arguments, only the filehandle and the name of the file. The mode of the file comes from the filename; if the filename starts (or ends) with any of several special characters, open() parses them off and uses them.

If you accidentally use a filename with those special characters with the two-arg form of open(), your code will not behave as you expect. This is especially a problem if you're not careful about sanitizing user input, and if any user input ever becomes part of a filename. Consider:

open my $fh, ">$filename" # INSECURE CODE; do not use
    or die "Can't write to '$filename': $!\n";

While this code appears to open $filename for writing, an insecure $filename could start with > to force appending mode, or - to open STDOUT (though I suspect you have to work really hard to force this). Likewise, code without any explicit mode in the second and final parameter is susceptible to any special mode characters.

Extracting file modes into a separate parameter to this function prevents Perl from parsing the filename at all and removes the possibility for this unintentional behavior. As Damian Conway has mentioned, using a separate file mode parameter also makes the intention of the code clearer:

open my $fh, '>', $filename # safer and clearer
    or die "Can't write to '$filename': $!\n";

The modern version of this code is safer and clearer, and it's been available since Perl 5.6.0, released on 22 March 2000. There's no reason not to use the modern version. (If you need your code to run on Perl 5.005, try a core module such as IO::Handle. If you need your code to run on older versions of Perl 5, you have my sympathy.)


There are more than two forms of open in Perl 5.

What if I want the magic - behavior? I think it would be silly to recode it with a three-argument open. Adding a space before the filename and never using the implied < goes a long way towards addressing your concerns.

If you want the magic behavior of the two-argument form, use it. Nothing stops you. (I've never seen it used in the real world, but I believe it exists.)

Yes, adding a space between the mode and the filename helps... but I dislike jamming two separate things together into one argument. This isn't chocolate and peanut butter, it's an adverb and a noun.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide



About this Entry

This page contains a single entry by chromatic published on April 19, 2010 2:55 PM.

Removing Friction was the previous entry in this blog.

The Thing about Volunteers and Civility is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by the Perl programming language

what is programming?