Thursday, July 21, 2011

on perl's open()

There's a minor brouhaha in the Perl community these days regarding perlopentut. One bone of contention regards the style of Perl that is shown to readers of the tutorial - ostensibly they're beginners to the language.


Another contentious aspect is that Tom Christiansen, the original author of the tutorial, sees the proposed changes as stomping across his authorship. This latter point is complicated a bit by the license on the tutorial, which allows anyone to make changes to it. (Tom's "I'll take my toys and go home," knee-jerk reaction was greeted with the equally inflammatory, "Neener neener.")




The "Modern Perl" movers-and-shakers would like to see something like this:


open FH, '>some-file.txt' or die "open some-file.txt: $!\n";


replaced with this:


open my $fh, '>', 'some-file.txt' or die "open some-file.txt: $!\n";


I personally prefer the three-arg form of open. I could tell you that it's because I like my filehandles to close themselves when they go out of scope, or that I care about the safeness of the three-arg over the two-arg. But really it's that I find FH makes my code look like it's shouting special magic at me, whereas $fh just tells me to relax: filehandles can be safely hidden inside a scalar. The $, which newcomers to Perl find so perlpexing, and which detractors of the language find so jangly to look at, is a soothing reassurance to my eyes.


Seriously. That's why I like the three-arg form of open(). Because it looks nicer to me. If I were interviewing, I'd mumble stuff about open() being safer in the three- than two-arg form. But I look at code all day long, so I choose to look at what I find to be pretty code.


Recently one of my colleagues pointed out a bug in one of the write-to-a-file routines that I dashed off inside some script. Despite being a perl developer for 6 years, and having 11 years experience with the language, I'd written:

open my $fh, '>', '/tmp/wherever' or die "open /tmp/wherever: $!\n";
...
print $fh, "here's the data I want logged\n";
...

There's a subtle bug there, which perl can't find. Here's two programs you can run side-by-side to compare. First, let's write to a file using the two-arg form of open():

1 #!/usr/bin/perl
2 
3 use strict;
4 use warnings;
5 
6 open FH, '>two-arg.txt' or die "two-arg.txt: $!\n";
7 print FH, "hello world\n";
8 close FH;

And here's the same program using the three-arg form of open():

1 #!/usr/bin/perl
2 
3 use strict;
4 use warnings;
5 
6 open my $fh, '>', 'three-arg.txt' or die "three-arg.txt: $!\n";
7 print $fh, "hello world\n";
8 close $fh;

Can you figure out the bug before hitting the jump?