tags:

views:

282

answers:

9

Are there any reasons to ever use the two-argument form of open(...) in Perl rather than the three-or-more-argument versions?

The only reason I can come up with is the obvious observation that the two-argument form is shorter. But assuming that verbosity is not an issue, are there any other reasons that would make you choose the two-argument form of open(...)?

A: 

I'm guessing you mean open(FH, '<filename.txt') as opposed to open(FH, '<', 'filename.txt') ?

I think it's just a matter of preference. I always use the former out of habit.

Rob
Compare open(FH, $foo) to open(FH, '<', $foo). The latter is in read-mode. Which mode is the former in? :-)
knorv
@knorv: exactly my point ;)
Abel
the default mode is read. If you want readability you could say `open(FH, "<$foo")` or just use `open(FH, '<', $foo)` if that's your preference. That's just the way I learned and have had no reason to change, it's just preference and habit.
Rob
To clarify, you can prepend the mode to the file name. "<filename.txt", ">>filename.txt", "|-filename.txt", etc...
Rob
Rob: My point is that open(FH, $foo) could be read ($foo = 'filename'), write ($foo = '> filename') or append ($foo = '>> filename').
knorv
.. and if $foo is a function of user input it could be a security issue if the two-argument version is used.
knorv
Well if you're storing the file mode and file name in the same variable, I can see how that would become confusing. Although if that's the case, i'm not sure how the 3 argument open would handle conflicting modes.
Rob
@Rob: isn't that precisely the issue? Reading a line of code that is instantly clear to you and other coders is many times more valuable then having to look up the declaration of a variable and how/where/if it changes to find out what mode (or what bug concerning the mode) is used in `open()`.
Abel
If you use 3-arg open, there's no need to "handle conflicting modes" because the mode is specified explicitly by the second argument. The content of the filename (third arg) is completely irrelevant to determining the mode - which is kind of the point of 3-arg open. Removing the mode from the filename closes down an entire class of potential security issues.
Dave Sherohman
equally, if you use 2-arg open, there's no need to "handle conflicting modes"; just specify your mode and filename, separated by a space
ysth
+2  A: 

When you are combining a string or using a variable, it can be rather unclear whether '<' or '>' etc is in already. In such cases, I personally prefer readability, which means, I use the longer form:

open($FILE, '>', $varfn);

When you simply use a constant, I prefer the ease-of-typing (and, actually, consider the short version better readable anyway, or at least even to the long version).

open($FILE, '>somefile.xxx');
Abel
If you downvote, please be so cordially to explain why so I can improve my apparent mishaps.
Abel
+3  A: 

If you're opening from a pipe, the three argument form isn't really helpful. Getting the equivalent of the three argument form involves doing a safe pipe open (open(FILE, '|-')) and then executing the program.

So for simple pipe opens (e.g. open(FILE, 'ps ax |')), the two argument syntax is much more compact.

William Rose
Or: `open(FILE, '-|', 'ps', 'ax')` (but I believe that was your own comment elsewhere as well)
Abel
+3  A: 

I think William's post pretty much hits it. Otherwise, the three-argument form is going to be more clear, as well as safer.

See also:

Ether
+1 for the excellent "best practice" story.
Abel
After reading your first link, someone points out there is an 3-or-more version of open() that does pipe opens. So you can do open(FILE, '-|', 'ps', 'ax')! The time I could have saved ... And, once again, TMTOWTDI.
William Rose
+4  A: 

Another small difference : the two argument form trim spaces

$foo = " fic";
open(MH, ">$foo");
print MH "toto\n";

Writes in a file named fic

On the other hand

$foo = " fic";
open(MH, ">", $foo);
print MH "toto\n";

Will write in a file whose name begin with a space.

For short admin scripts with user input (or configuration file input), not having to bother with such details as trimming filenames is nice.

kriss
At the price of potentially opening up to security issues.
tsee
In the general case, yes, but I tend to read "short admin scripts" to mean "things that will be run on the command line under the uid of the person running it", so the script won't be allowed (by the OS) to do anything the user would not be able to do on his own by more direct means.
Dave Sherohman
You're not really trimming the filename, Perl simply allows whitespace after the `>` or `|`, possibly because some systems require whitespace, more likely to be able to simply give multi-argument commands. On some systems (Windows) a filename starting with a space is legal (though few programs can deal with it). If you need to open a file that has a space, the opposite is true, you *have to use the long version.*
Abel
@Abel: no, you don't. leading spaces can be preserved simply by using a non-relative path or prefixing by ./ or OS-eqivalent. trailing spaces can be preserved by putting \0 after the filename.
ysth
+4  A: 

The two argument form of open was the only form supported by some old versions of perl.

Alan Haggai Alavi
Good point. In which version was it added?
knorv
5.6.0. There so few 5.5 users left that unless you specifically need to support 5.5 its not worth it. http://perldoc.perl.org/perl56delta.html#open%28%29-with-more-than-two-arguments
Schwern
+6  A: 

One- and two-arg open applies any default layers specified with the -C switch or open pragma. Three-arg open does not. In my opinion, this functional difference is the strongest reason to choose one or the other (and the choice will vary depending what you are opening). Which is easiest or most descriptive or "safest" (you can safely use two-arg open with arbitrary filenames, it's just not as convenient) take a back seat in module code; in script code you have more discretion to choose whether you will support default layers or not.

Also, one-arg open is needed for Damian Conway's file slurp operator

$_ = "filename";
$contents = readline!open(!((*{!$_},$/)=\$_));
ysth
Arg! Perl Golf. Remember Python guys are looking over your shoulder muttering "told you so!"
tsee
@tsee: the "Damian Conway" bit is supposed to warn you that it's not something you'd actually use. File::Slurp::read_file is shorter, anyway.
ysth
+3  A: 

One reason to use the two-argument version of open is if you want to open something which might be a pipe, or a file. If you have one function

sub strange
{
     my ($file) = @_;
     open my $input, $file or die $!;
}

then you want to call this either with a filename like "file":

strange ("file");

or a pipe like "zcat file.gz |"

strange ("zcat file.gz |");

depending on the situation of the file you find, then the two-argument version may be used. You will actually see the above construction in "legacy" Perl. However, the most sensible thing might be to open the filehandle appropriately and send the filehandle to the function rather than using the file name like this.

Kinopiko
+1 for using a lexical filehandle
Dave Sherohman
+4  A: 

Imagine you are writing a utility that accepts an input file name. People with reasonable Unix experience are used to substituting - for STDIN. Perl handles that automatically only when the magical form is used where the mode characters and file name are one string, else you have to handle this and similar special cases yourself. This is a somewhat common gotcha, I am surprised no one has posted that yet. Proof:

use IO::File qw();
my $user_supplied_file_name = '-';

IO::File->new($user_supplied_file_name, 'r') or warn "IO::File/non-magical mode - $!\n";
IO::File->new("<$user_supplied_file_name")   or warn "IO::File/magical mode - $!\n";
open my $fh1, '<', $user_supplied_file_name  or warn "non-magical open - $!\n";
open my $fh2, "<$user_supplied_file_name"    or warn "magical open - $!\n";

__DATA__
IO::File/non-magical mode - No such file or directory
non-magical open - No such file or directory

Vote me up, I can use the rep points. ☻

daxim