Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PATCH] [DOCS] Modernize perlopentut.pod #11502

Closed
p5pRT opened this issue Jul 14, 2011 · 20 comments
Closed

[PATCH] [DOCS] Modernize perlopentut.pod #11502

p5pRT opened this issue Jul 14, 2011 · 20 comments
Labels

Comments

@p5pRT
Copy link

p5pRT commented Jul 14, 2011

Migrated from rt.perl.org#94860 (status was 'resolved')

Searchable as RT94860$

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2011

From doherty@cs.dal.ca

This revises and rearranges perlopentut.pod to reflect more modern
usages of open. In particular, it emphasisizes the use of 3-arg
open over 2-arg, and the use of lexical filehandles (including
an explanation of terminology). It also cleans up quoting and
trailing whitespace, so you may wish to use -w to reduce the number
of changes you see.

Thanks to Matt Trout for his encouragement.


pod/perlopentut.pod | 339 +++++++++++++++++++++++++++------------------------
1 files changed, 181 insertions(+), 158 deletions(-)

Inline Patch
diff --git a/pod/perlopentut.pod b/pod/perlopentut.pod
index 4bb43bf..04b4f20 100644
--- a/pod/perlopentut.pod
+++ b/pod/perlopentut.pod
@@ -7,7 +7,7 @@ perlopentut - tutorial on opening things in Perl
 Perl has two simple, built-in ways to open files: the shell way for
 convenience, and the C way for precision.  The shell way also has 2- and
 3-argument forms, which have different semantics for handling the filename.
-The choice is yours.
+You'll probably want to use the 3-argument form.
 
 =head1 Open E<agrave> la shell
 
@@ -19,7 +19,7 @@ from the shell:
     $ myprogram    <  inputfile
     $ myprogram    >  outputfile
     $ myprogram    >> outputfile
-    $ myprogram    |  otherprogram 
+    $ myprogram    |  otherprogram
     $ otherprogram |  myprogram
 
 And here are some more advanced examples:
@@ -35,97 +35,54 @@ virtually the same syntax as the shell.
 
 =head2 Simple Opens
 
-The C<open> function takes two arguments: the first is a filehandle,
-and the second is a single string comprising both what to open and how
-to open it.  C<open> returns true when it works, and when it fails,
-returns a false value and sets the special variable C<$!> to reflect
-the system error.  If the filehandle was previously opened, it will
-be implicitly closed first.
+The C<open> function takes three arguments: the first is a filehandle,
+or a reference to a filehandle (which is preferred); the second is a
+string specifying how to open the file (for reading, writing, appending,
+etc.); the third is what file to open. Since Perl 5.6, if the argument
+specifying the filehandle is undefined, then Perl will create a
+filehandle, and put a reference to it into that argument. This is called
+a "lexical" ("my") or "indirect" filehandle. We'll call it "lexical" here.
 
-For example:
-
-    open(INFO,      "datafile") || die("can't open datafile: $!");
-    open(INFO,   "<  datafile") || die("can't open datafile: $!");
-    open(RESULTS,">  runstats") || die("can't open runstats: $!");
-    open(LOG,    ">> logfile ") || die("can't open logfile:  $!");
-
-If you prefer the low-punctuation version, you could write that this way:
-
-    open INFO,   "<  datafile"  or die "can't open datafile: $!";
-    open RESULTS,">  runstats"  or die "can't open runstats: $!";
-    open LOG,    ">> logfile "  or die "can't open logfile:  $!";
-
-A few things to notice.  First, the leading C<< < >> is optional.
-If omitted, Perl assumes that you want to open the file for reading.
-
-Note also that the first example uses the C<||> logical operator, and the
-second uses C<or>, which has lower precedence.  Using C<||> in the latter
-examples would effectively mean
-
-    open INFO, ( "<  datafile"  || die "can't open datafile: $!" );
-
-which is definitely not what you want.
-
-The other important thing to notice is that, just as in the shell,
-any whitespace before or after the filename is ignored.  This is good,
-because you wouldn't want these to do different things:
-
-    open INFO,   "<datafile"   
-    open INFO,   "< datafile" 
-    open INFO,   "<  datafile"
-
-Ignoring surrounding whitespace also helps for when you read a filename
-in from a different file, and forget to trim it before opening:
+C<open> returns true when it works, and when it fails, returns a false
+value and sets the special variable C<$!> to reflect the system error.
+You can use the L<autodie> pragma to make it die with an exception,
+if you prefer to avoid writing repetitive error-handling code yourself.
 
-    $filename = <INFO>;         # oops, \n still there
-    open(EXTRA, "< $filename") || die "can't open $filename: $!";
+If the filehandle was previously opened, it will be implicitly closed
+first. This allows you to re-use the same reference rather than create
+a new one for every filehandle you require.
 
-This is not a bug, but a feature.  Because C<open> mimics the shell in
-its style of using redirection arrows to specify how to open the file, it
-also does so with respect to extra whitespace around the filename itself
-as well.  For accessing files with naughty names, see 
-L<"Dispelling the Dweomer">.
+Here are some examples of the 3-argument form of open:
 
-There is also a 3-argument version of C<open>, which lets you put the
-special redirection characters into their own argument:
+    open(my $info,    '<', 'datafile') || die("Can't open datafile: $!");
+    open(my $results, '>', 'runstats') || die("Can't open runstats: $!");
+    open(my $log,     '>>', 'logfile') || die("Can't open logfile:  $!");
 
-    open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
-
-In this case, the filename to open is the actual string in C<$datafile>,
-so you don't have to worry about C<$datafile> containing characters
-that might influence the open mode, or whitespace at the beginning of
-the filename that would be absorbed in the 2-argument version.  Also,
-any reduction of unnecessary string interpolation is a good thing.
+If you prefer the low-punctuation version, you could write that this way:
 
-=head2 Indirect Filehandles
+    open my $info,    '<', 'datafile'  or die "Can't open datafile: $!";
+    open my $results, '>', 'runstats'  or die "Can't open runstats: $!";
+    open my $log,     '>>', 'logfile'  or die "Can't open logfile:  $!";
 
-C<open>'s first argument can be a reference to a filehandle.  As of
-perl 5.6.0, if the argument is uninitialized, Perl will automatically
-create a filehandle and put a reference to it in the first argument,
-like so:
+A few things to notice. The first example uses the C<||> logical operator,
+and the second uses C<or>, which has lower precedence.  Using C<||> in the
+latter examples would effectively mean
 
-    open( my $in, $infile )   or die "Couldn't read $infile: $!";
-    while ( <$in> ) {
-	# do something with $_
-    }
-    close $in;
+    open my $info, ( '<', 'datafile'  || die "Can't open datafile: $!" );
 
-Indirect filehandles make namespace management easier.  Since filehandles
-are global to the current package, two subroutines trying to open
-C<INFILE> will clash.  With two functions opening indirect filehandles
-like C<my $infile>, there's no clash and no need to worry about future
-conflicts.
+which is definitely not what you want.
 
-Another convenient behavior is that an indirect filehandle automatically
-closes when there are no more references to it:
+When the filehandle is specified as a reference, it is a "lexical" filehandle,
+which is automatically closed when there are no more references to it:
 
     sub firstline {
-	open( my $in, shift ) && return scalar <$in>;
-	# no close() required
+        open( my $in, shift ) && return scalar <$in>;
+        # no close() required
     }
 
-Indirect filehandles also make it easy to pass filehandles to and return
-filehandles from subroutines:
+Lexical filehandles also make it easy to pass filehandles info subroutines, or
+return a filehandle from a subroutine--just pass the reference like any other
+reference:
 
     for my $file ( qw(this.conf that.conf) ) {
         my $fin = open_or_throw('<', $file);
@@ -141,31 +98,92 @@ filehandles from subroutines:
         return $h;
     }
 
+=head2 Bareword Filehandles
+
+C<open>'s first argument is normally a reference to a filehandle (a "lexical"
+filehandle), making namespace management easier:
+
+    open my $fh, '<', 'filename' or die "Couldn't open filename: $!";
+    while (<$fh>) {...} # $fh is called "lexical" ("my") or "indirect"
+
+There is another way of specifying filehandles directly--"bareword" filehandles:
+
+    open INFO, '<', 'datafile' or die "Couldn't open datafile: $!";
+    while (<INFO>) {...} # INFO is called "bareword", "direct", or "global"
+
+Since bareword filehandles are global to the current package, two subroutines
+trying to open C<INFILE> will clash. With two functions opening lexical
+filehandles like C<my $infile>, there's no clash and no need to worry about
+future conflicts. Lexical filehandles are also automatically closed when they
+fall out of scope in the same way that lexical variables are garbage-collected.
+
+Bareword filehandles are often used to refer to the standard input (C<*STDIN>),
+output (C<*STDOUT>), and error filehandles (C<*STDERR>), but you can use
+them for any filehandle if you wish.
+
+=head2 Two-Argument Open
+
+There is also an old 2-argument version of C<open>, which lets you put the
+special redirection characters and the filename into the same argument:
+
+    open(my $info, "> $datafile" ) || die "Can't create $datafile: $!";
+
+In this case, the filename to open is not a separate argument, so
+you have to worry about C<$datafile> containing characters that might
+influence the open mode, or whitespace in the second argument that wouldn't
+be a problem in the 3-argument version.
+
+Another important thing to notice is that, just as in the shell, any whitespace
+before or after the filename is ignored.  This is good, because you wouldn't
+want these to do different things:
+
+    open my $info,   '<datafile'
+    open my $info,   '< datafile'
+    open my $info,   '<  datafile'
+
+Ignoring surrounding whitespace also helps for when you read a filename in from
+a different file, and forget to trim it before opening:
+
+    $filename = <$info>;         # oops, \n still there
+    open(my $extra, "< $filename") || die "can't open $filename: $!";
+
+This is a feature, not a bug.  Because C<open> mimics the shell in its style of
+using redirection arrows to specify how to open the file, it also does so with
+respect to extra whitespace around the filename itself as well.  For accessing
+files with naughty names, see L<"Dispelling the Dweomer">.
+
+When opening a file, the leading C<< < >> is optional. If omitted, Perl assumes
+that you want to open the file for reading:
+
+    open(my $info, $datafile) || die("Can't open $datafile: $!");
+
 =head2 Pipe Opens
 
 In C, when you want to open a file using the standard I/O library,
 you use the C<fopen> function, but when opening a pipe, you use the
 C<popen> function.  But in the shell, you just use a different redirection
-character.  That's also the case for Perl.  The C<open> call 
-remains the same--just its argument differs.  
+character.  That's also the case for Perl.  The C<open> call
+remains the same--just its argument differs.
 
 If the leading character is a pipe symbol, C<open> starts up a new
 command and opens a write-only filehandle leading into that command.
 This lets you write into that handle and have what you write show up on
 that command's standard input.  For example:
 
-    open(PRINTER, "| lpr -Plp1")    || die "can't run lpr: $!";
-    print PRINTER "stuff\n";
-    close(PRINTER)                  || die "can't close lpr: $!";
+    open(my $printer, '| lpr -Plp1') || die "can't run lpr: $!";
+    print $printer "stuff\n";
+    close($printer)                  || die "can't close lpr: $!";
 
 If the trailing character is a pipe, you start up a new command and open a
 read-only filehandle leading out of that command.  This lets whatever that
 command writes to its standard output show up on your handle for reading.
 For example:
 
-    open(NET, "netstat -i -n |")    || die "can't fork netstat: $!";
-    while (<NET>) { }               # do something with input
-    close(NET)                      || die "can't close netstat: $!";
+    open(my $net, 'netstat -i -n |') || die "can't fork netstat: $!";
+    while (<$net>) {
+        # do something with input
+    }
+    close($net)                      || die "can't close netstat: $!";
 
 What happens if you try to open a pipe to or from a non-existent
 command?  If possible, Perl will detect the failure and set C<$!> as
@@ -178,8 +196,8 @@ failure if Perl can't even run the shell.  See L<perlfaq8/"How can I
 capture STDERR from an external command?"> to see how to cope with
 this.  There's also an explanation in L<perlipc>.
 
-If you would like to open a bidirectional pipe, the IPC::Open2
-library will handle this for you.  Check out 
+If you would like to open a bidirectional pipe, the L<IPC::Open2>
+library will handle this for you.  Check out
 L<perlipc/"Bidirectional Communication with Another Process">
 
 perl-5.6.x introduced a version of piped open that executes a process
@@ -220,7 +238,7 @@ access the standard output.
 If minus can be used as the default input or default output, what happens
 if you open a pipe into or out of minus?  What's the default command it
 would run?  The same script as you're currently running!  This is actually
-a stealth C<fork> hidden inside an C<open> call.  See 
+a stealth C<fork> hidden inside an C<open> call.  See
 L<perlipc/"Safe Pipe Opens"> for details.
 
 =head2 Mixing Reads and Writes
@@ -233,13 +251,13 @@ existing one.  On the other hand, using a greater-than always clobbers
 if there isn't an old one.  Adding a "+" for read-write doesn't affect
 whether it only works on existing files or always clobbers existing ones.
 
-    open(WTMP, "+< /usr/adm/wtmp") 
+    open(my $wtmp, '+< /usr/adm/wtmp')
         || die "can't open /usr/adm/wtmp: $!";
 
-    open(SCREEN, "+> lkscreen")
+    open(my $screen, '+> lkscreen')
         || die "can't open lkscreen: $!";
 
-    open(LOGFILE, "+>> /var/log/applog")
+    open($logfile, '+>> /var/log/applog')
         || die "can't open /var/log/applog: $!";
 
 The first one won't create a new file, and the second one will always
@@ -262,14 +280,14 @@ on the end:
     $ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]
 
 This is a short cut for some renaming games that are really
-the best way to update textfiles.  See the second question in 
+the best way to update textfiles.  See the second question in
 L<perlfaq5> for more details.
 
-=head2 Filters 
+=head2 Filters
 
 One of the most common uses for C<open> is one you never
 even notice.  When you process the ARGV filehandle using
-C<< <ARGV> >>, Perl actually does an implicit open 
+C<< <ARGV> >>, Perl actually does an implicit open
 on each file in @ARGV.  Thus a program called like this:
 
     $ myprogram file1 file2 file3
@@ -279,7 +297,7 @@ using a construct no more complex than:
 
     while (<>) {
         # do something with $_
-    } 
+    }
 
 If @ARGV is empty when the loop first begins, Perl pretends you've opened
 up minus, that is, the standard input.  In fact, $ARGV, the currently
@@ -294,17 +312,17 @@ simple ones by hand, the Getopts modules are good for this:
     use Getopt::Std;
 
     # -v, -D, -o ARG, sets $opt_v, $opt_D, $opt_o
-    getopts("vDo:");            
+    getopts('vDo:');
 
     # -v, -D, -o ARG, sets $args{v}, $args{D}, $args{o}
-    getopts("vDo:", \%args);    
+    getopts('vDo:', \%args);
 
 Or the standard Getopt::Long module to permit named arguments:
 
     use Getopt::Long;
-    GetOptions( "verbose"  => \$verbose,        # --verbose
-                "Debug"    => \$debug,          # --Debug
-                "output=s" => \$output );       
+    GetOptions( 'verbose'  => \$verbose,        # --verbose
+                'Debug'    => \$debug,          # --Debug
+                'output=s' => \$output );
 	    # --output=somestring or --output somestring
 
 Another reason for preprocessing arguments is to make an empty
@@ -329,7 +347,7 @@ Here's an example:
                     ? '< /etc/passwd'
                     : 'ypcat passwd |';
 
-    open(PWD, $pwdinfo)                 
+    open(my $pwd, $pwdinfo)
                 or die "can't open $pwdinfo: $!";
 
 This sort of thing also comes into play in filter processing.  Because
@@ -367,7 +385,7 @@ If you want the convenience of the shell, then Perl's C<open> is
 definitely the way to go.  On the other hand, if you want finer precision
 than C's simplistic fopen(3S) provides you should look to Perl's
 C<sysopen>, which is a direct hook into the open(2) system call.
-That does mean it's a bit more involved, but that's the price of 
+That does mean it's a bit more involved, but that's the price of
 precision.
 
 C<sysopen> takes 3 (or 4) arguments.
@@ -413,24 +431,24 @@ but you'll get the idea.
 
 To open a file for reading:
 
-    open(FH, "< $path");
-    sysopen(FH, $path, O_RDONLY);
+    open(my $fh, "< $path");
+    sysopen(my $fh, $path, O_RDONLY);
 
 To open a file for writing, creating a new file if needed or else truncating
 an old file:
 
-    open(FH, "> $path");
-    sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT);
+    open(my $fh, "> $path");
+    sysopen(my $fh, $path, O_WRONLY | O_TRUNC | O_CREAT);
 
 To open a file for appending, creating one if necessary:
 
-    open(FH, ">> $path");
-    sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT);
+    open(my $fh, ">> $path");
+    sysopen(my $fh, $path, O_WRONLY | O_APPEND | O_CREAT);
 
 To open a file for update, where the file must already exist:
 
-    open(FH, "+< $path");
-    sysopen(FH, $path, O_RDWR);
+    open(my $fh, "+< $path");
+    sysopen(my $fh, $path, O_RDWR);
 
 And here are things you can do with C<sysopen> that you cannot do with
 a regular C<open>.  As you'll see, it's just a matter of controlling the
@@ -439,23 +457,23 @@ flags in the third argument.
 To open a file for writing, creating a new file which must not previously
 exist:
 
-    sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT);
+    sysopen(my $fh, $path, O_WRONLY | O_EXCL | O_CREAT);
 
 To open a file for appending, where that file must already exist:
 
-    sysopen(FH, $path, O_WRONLY | O_APPEND);
+    sysopen(my $fh, $path, O_WRONLY | O_APPEND);
 
 To open a file for update, creating a new file if necessary:
 
-    sysopen(FH, $path, O_RDWR | O_CREAT);
+    sysopen(my $fh, $path, O_RDWR | O_CREAT);
 
 To open a file for update, where that file must not already exist:
 
-    sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT);
+    sysopen(my $fh, $path, O_RDWR | O_EXCL | O_CREAT);
 
 To open a file without blocking, creating one if necessary:
 
-    sysopen(FH, $path, O_WRONLY | O_NONBLOCK | O_CREAT);
+    sysopen(my $fh, $path, O_WRONLY | O_NONBLOCK | O_CREAT);
 
 =head2 Permissions E<agrave> la mode
 
@@ -558,7 +576,7 @@ filename that starts with whitespace.  Trailing whitespace is protected
 by appending an ASCII NUL byte (C<"\0">) at the end of the string.
 
     $file =~ s#^(\s)#./$1#;
-    open(FH, "< $file\0")   || die "can't open $file: $!";
+    open(my $fh, "< $file\0")   || die "can't open $file: $!";
 
 This assumes, of course, that your system considers dot the current
 working directory, slash the directory separator, and disallows ASCII
@@ -571,16 +589,16 @@ use a slash.  Maybe C<sysopen> isn't such a bad idea after all.
 If you want to use C<< <ARGV> >> processing in a totally boring
 and non-magical way, you could do this first:
 
-    #   "Sam sat on the ground and put his head in his hands.  
-    #   'I wish I had never come here, and I don't want to see 
+    #   "Sam sat on the ground and put his head in his hands.
+    #   'I wish I had never come here, and I don't want to see
     #   no more magic,' he said, and fell silent."
-    for (@ARGV) { 
+    for (@ARGV) {
         s#^([^./])#./$1#;
         $_ .= "\0";
-    } 
-    while (<>) {  
+    }
+    while (<>) {
         # now process $_
-    } 
+    }
 
 But be warned that users will not appreciate being unable to use "-"
 to mean standard input, per the standard convention.
@@ -601,26 +619,32 @@ temporarily, then all you have to do is this:
     open($path, "< $path") || die "can't open $path: $!";
     while (<$path>) {
         # whatever
-    } 
+    }
 
 Since you're using the pathname of the file as its handle,
 you'll get warnings more like
 
     Some warning at scriptname line 29, </etc/motd> line 7.
 
+A better alternative is to use the L<autodie> pragma, which is included
+in the Perl core distribution as of v5.10.1 (and can be installed as far
+back as Perl 5.8). Autodie makes C<open> throw an exception object that
+provides excellent error messages.
+
 =head2 Single Argument Open
 
-Remember how we said that Perl's open took two arguments?  That was a
-passive prevarication.  You see, it can also take just one argument.
-If and only if the variable is a global variable, not a lexical, you
-can pass C<open> just one argument, the filehandle, and it will 
-get the path from the global scalar variable of the same name.
+Remember how we said that Perl's open took three or two arguments?
+That was a passive prevarication.  You see, it can also take just
+one argument. If and only if the variable is a global variable,
+not a lexical, you can pass C<open> just one argument, the filehandle,
+and it will get the path from the global scalar variable of the same
+name:
 
     $FILE = "/etc/motd";
     open FILE or die "can't open $FILE: $!";
     while (<FILE>) {
         # whatever
-    } 
+    }
 
 Why is this here?  Someone has to cater to the hysterical porpoises.
 It's something that's been in Perl since the very beginning, if not
@@ -640,11 +664,11 @@ failure status.
 You don't have to accept the STDIN and STDOUT you were given.  You are
 welcome to reopen them if you'd like.
 
-    open(STDIN, "< datafile")
-	|| die "can't open datafile: $!";
+    open(STDIN, '< datafile')
+	|| die "Can't open datafile: $!";
 
-    open(STDOUT, "> output")
-	|| die "can't open output: $!";
+    open(STDOUT, '> output')
+	|| die "Can't open output: $!";
 
 And then these can be accessed directly or passed on to subprocesses.
 This makes it look as though the program were initially invoked
@@ -652,9 +676,8 @@ with those redirections from the command line.
 
 It's probably more interesting to connect these to pipes.  For example:
 
-    $pager = $ENV{PAGER} || "(less || more)";
-    open(STDOUT, "| $pager")
-	|| die "can't fork a pager: $!";
+    $pager = $ENV{PAGER} || '(less || more)';
+    open(STDOUT, "| $pager") || die "can't fork a pager: $!";
 
 This makes it appear as though your program were called with its stdout
 already piped into your pager.  You can also use this kind of thing
@@ -665,18 +688,18 @@ just in a different process:
     head(100);
     while (<>) {
         print;
-    } 
+    }
 
     sub head {
         my $lines = shift || 20;
-        return if $pid = open(STDOUT, "|-");       # return if parent
+        return if $pid = open(STDOUT, '|-');       # return if parent
         die "cannot fork: $!" unless defined $pid;
         while (<STDIN>) {
             last if --$lines < 0;
             print;
-        } 
+        }
         exit;
-    } 
+    }
 
 This technique can be applied to repeatedly push as many filters on your
 output stream as you wish.
@@ -694,7 +717,7 @@ just in case.
 
     if (-l $file || ! -f _) {
         print "$file is not a plain file\n";
-    } 
+    }
 
 What other kinds of files are there than, well, files?  Directories,
 symbolic links, named pipes, Unix-domain sockets, and block and character
@@ -704,14 +727,14 @@ Not all plain files are text files.  That's why there are separate C<-f>
 and C<-T> file tests.
 
 To open a directory, you should use the C<opendir> function, then
-process it with C<readdir>, carefully restoring the directory 
+process it with C<readdir>, carefully restoring the directory
 name if necessary:
 
-    opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
-    while (defined($file = readdir(DIR))) {
+    opendir(my $dir, $dirname) or die "can't opendir $dirname: $!";
+    while (defined($file = readdir($dir))) {
         # do something with "$dirname/$file"
     }
-    closedir(DIR);
+    closedir($dir);
 
 If you want to process directories recursively, it's better to use the
 File::Find module.  For example, this prints out all files recursively
@@ -734,8 +757,8 @@ C<readlink> is called for:
             print "$file points to $whither\n";
         } else {
             print "$file points nowhere: $!\n";
-        } 
-    } 
+        }
+    }
 
 =head2 Opening Named Pipes
 
@@ -767,9 +790,9 @@ With descriptors that you haven't opened using C<sysopen>, such as
 sockets, you can set them to be non-blocking using C<fcntl>:
 
     use Fcntl;
-    my $old_flags = fcntl($handle, F_GETFL, 0) 
+    my $old_flags = fcntl($handle, F_GETFL, 0)
         or die "can't get flags: $!";
-    fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK) 
+    fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK)
         or die "can't set non blocking: $!";
 
 Rather than losing yourself in a morass of twisting, turning C<ioctl>s,
@@ -784,8 +807,8 @@ Check out Term::ReadKey and Term::ReadLine.
 =head2 Opening Sockets
 
 What else can you open?  To open a connection using sockets, you won't use
-one of Perl's two open functions.  See 
-L<perlipc/"Sockets: Client/Server Communication"> for that.  Here's an 
+one of Perl's two open functions.  See
+L<perlipc/"Sockets: Client/Server Communication"> for that.  Here's an
 example.  Once you have it, you can use FH as a bidirectional filehandle.
 
     use IO::Socket;
@@ -814,7 +837,7 @@ handles before doing regular I/O on them:
 
     binmode(STDIN);
     binmode(STDOUT);
-    while (<STDIN>) { print } 
+    while (<STDIN>) { print }
 
 Passing C<sysopen> a non-standard flag option will also open the file in
 binary mode on those systems that support it.  This is the equivalent of
@@ -834,7 +857,7 @@ sneaky data mutilation behind your back.
 
     while (sysread(WHENCE, $buf, 1024)) {
         syswrite(WHITHER, $buf, length($buf));
-    } 
+    }
 
 Depending on the vicissitudes of your runtime system, even these calls
 may need C<binmode> or C<O_BINARY> first.  Systems known to be free of
@@ -897,7 +920,7 @@ if you're going to be blocking:
 	print "Waiting for lock...";
 	flock(FH, LOCK_SH)  or die "can't lock filename: $!";
 	print "got it.\n"
-    } 
+    }
     # now read from FH
 
 To get an exclusive lock, typically used for writing, you have to be
@@ -974,7 +997,7 @@ The two-argument form of C<binmode> is being used, for example
 For more detailed discussion about PerlIO see L<PerlIO>;
 for more detailed discussion about Unicode and I/O see L<perluniintro>.
 
-=head1 SEE ALSO 
+=head1 SEE ALSO
 
 The C<open> and C<sysopen> functions in perlfunc(1);
 the system open(2), dup(2), fopen(3), and fdopen(3) manpages;
@@ -982,7 +1005,7 @@ the POSIX documentation.
 
 =head1 AUTHOR and COPYRIGHT
 
-Copyright 1998 Tom Christiansen.  
+Copyright 1998 Tom Christiansen.
 
 This documentation is free; you can redistribute it and/or modify it
 under the same terms as Perl itself.
-- 
1.7.6

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2011

From @jkeenan

On Thu Jul 14 16​:40​:18 2011, doherty wrote​:

This revises and rearranges perlopentut.pod to reflect more modern
usages of open. In particular, it emphasisizes the use of 3-arg
open over 2-arg, and the use of lexical filehandles (including
an explanation of terminology). It also cleans up quoting and
trailing whitespace, so you may wish to use -w to reduce the number
of changes you see.

Thanks to Matt Trout for his encouragement.

Since the original submission was large and the patch was submitted
inline, it did not completely display in the RT GUI. Hence, the patch
may not have gotten the consideration it deserved.

I extracted the patch to a separate file and tried to apply it in a
branch. It didn't apply cleanly, so I did what I hope is a reasonable
manual application of the rejected hunks. Please review the attached
patch (or the original, if you saw it via the mailing list).

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2011

From @jkeenan

0001-perlopentut.pod-patch-based-on-submission-by-Mike-Do.patch
From 654bf402eea5b5d115b08bf1dec41c222913726d Mon Sep 17 00:00:00 2001
From: jkeenan <jkeenan@cpan.org>
Date: Wed, 14 Dec 2011 19:11:48 -0500
Subject: [PATCH] perlopentut.pod: patch based on submission by Mike Doherty in RT #94860.

---
 pod/perlopentut.pod |  345 +++++++++++++++++++++++++++------------------------
 1 files changed, 184 insertions(+), 161 deletions(-)

diff --git a/pod/perlopentut.pod b/pod/perlopentut.pod
index 4bb43bf..8d2725c 100644
--- a/pod/perlopentut.pod
+++ b/pod/perlopentut.pod
@@ -7,7 +7,7 @@ perlopentut - tutorial on opening things in Perl
 Perl has two simple, built-in ways to open files: the shell way for
 convenience, and the C way for precision.  The shell way also has 2- and
 3-argument forms, which have different semantics for handling the filename.
-The choice is yours.
+You'll probably want to use the 3-argument form.
 
 =head1 Open E<agrave> la shell
 
@@ -19,7 +19,7 @@ from the shell:
     $ myprogram    <  inputfile
     $ myprogram    >  outputfile
     $ myprogram    >> outputfile
-    $ myprogram    |  otherprogram 
+    $ myprogram    |  otherprogram
     $ otherprogram |  myprogram
 
 And here are some more advanced examples:
@@ -35,97 +35,54 @@ virtually the same syntax as the shell.
 
 =head2 Simple Opens
 
-The C<open> function takes two arguments: the first is a filehandle,
-and the second is a single string comprising both what to open and how
-to open it.  C<open> returns true when it works, and when it fails,
-returns a false value and sets the special variable C<$!> to reflect
-the system error.  If the filehandle was previously opened, it will
-be implicitly closed first.
+The C<open> function takes three arguments: the first is a filehandle,
+or a reference to a filehandle (which is preferred); the second is a
+string specifying how to open the file (for reading, writing, appending,
+etc.); the third is what file to open. Since Perl 5.6, if the argument
+specifying the filehandle is undefined, then Perl will create a
+filehandle, and put a reference to it into that argument. This is called
+a "lexical" ("my") or "indirect" filehandle. We'll call it "lexical" here.
 
-For example:
-
-    open(INFO,      "datafile") || die("can't open datafile: $!");
-    open(INFO,   "<  datafile") || die("can't open datafile: $!");
-    open(RESULTS,">  runstats") || die("can't open runstats: $!");
-    open(LOG,    ">> logfile ") || die("can't open logfile:  $!");
-
-If you prefer the low-punctuation version, you could write that this way:
+C<open> returns true when it works, and when it fails, returns a false
+value and sets the special variable C<$!> to reflect the system error.
+You can use the L<autodie> pragma to make it die with an exception,
+if you prefer to avoid writing repetitive error-handling code yourself.
 
-    open INFO,   "<  datafile"  or die "can't open datafile: $!";
-    open RESULTS,">  runstats"  or die "can't open runstats: $!";
-    open LOG,    ">> logfile "  or die "can't open logfile:  $!";
+If the filehandle was previously opened, it will be implicitly closed
+first. This allows you to re-use the same reference rather than create
+a new one for every filehandle you require.
 
-A few things to notice.  First, the leading C<< < >> is optional.
-If omitted, Perl assumes that you want to open the file for reading.
-
-Note also that the first example uses the C<||> logical operator, and the
-second uses C<or>, which has lower precedence.  Using C<||> in the latter
-examples would effectively mean
-
-    open INFO, ( "<  datafile"  || die "can't open datafile: $!" );
-
-which is definitely not what you want.
+Here are some examples of the 3-argument form of open:
 
-The other important thing to notice is that, just as in the shell,
-any whitespace before or after the filename is ignored.  This is good,
-because you wouldn't want these to do different things:
+    open(my $info,    '<', 'datafile') || die("can't open datafile: $!");
+    open(my $results, '>', 'runstats') || die("can't open runstats: $!");
+    open(my $log,     '>>', 'logfile') || die("can't open logfile:  $!");
 
-    open INFO,   "<datafile"   
-    open INFO,   "< datafile" 
-    open INFO,   "<  datafile"
-
-Ignoring surrounding whitespace also helps for when you read a filename
-in from a different file, and forget to trim it before opening:
-
-    $filename = <INFO>;         # oops, \n still there
-    open(EXTRA, "< $filename") || die "can't open $filename: $!";
-
-This is not a bug, but a feature.  Because C<open> mimics the shell in
-its style of using redirection arrows to specify how to open the file, it
-also does so with respect to extra whitespace around the filename itself
-as well.  For accessing files with naughty names, see 
-L<"Dispelling the Dweomer">.
-
-There is also a 3-argument version of C<open>, which lets you put the
-special redirection characters into their own argument:
-
-    open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
-
-In this case, the filename to open is the actual string in C<$datafile>,
-so you don't have to worry about C<$datafile> containing characters
-that might influence the open mode, or whitespace at the beginning of
-the filename that would be absorbed in the 2-argument version.  Also,
-any reduction of unnecessary string interpolation is a good thing.
+If you prefer the low-punctuation version, you could write that this way:
 
-=head2 Indirect Filehandles
+    open my $info,    '<', 'datafile'  or die "can't open datafile: $!";
+    open my $results, '>', 'runstats'  or die "can't open runstats: $!";
+    open my $log,     '>>', 'logfile'  or die "can't open logfile:  $!";
 
-C<open>'s first argument can be a reference to a filehandle.  As of
-perl 5.6.0, if the argument is uninitialized, Perl will automatically
-create a filehandle and put a reference to it in the first argument,
-like so:
+A few things to notice. The first example uses the C<||> logical operator,
+and the second uses C<or>, which has lower precedence.  Using C<||> in the
+latter examples would effectively mean
 
-    open( my $in, $infile )   or die "Couldn't read $infile: $!";
-    while ( <$in> ) {
-	# do something with $_
-    }
-    close $in;
+    open my $info, ( '<', 'datafile'  || die "can't open datafile: $!" );
 
-Indirect filehandles make namespace management easier.  Since filehandles
-are global to the current package, two subroutines trying to open
-C<INFILE> will clash.  With two functions opening indirect filehandles
-like C<my $infile>, there's no clash and no need to worry about future
-conflicts.
+which is definitely not what you want.
 
-Another convenient behavior is that an indirect filehandle automatically
-closes when there are no more references to it:
+When the filehandle is specified as a reference, it is a "lexical" filehandle,
+which is automatically closed when there are no more references to it:
 
-    sub firstline {
-	open( my $in, shift ) && return scalar <$in>;
-	# no close() required
-    }
+      sub firstline {
+        open( my $in, shift ) && return scalar <$in>;
+        # no close() required
+      }
 
-Indirect filehandles also make it easy to pass filehandles to and return
-filehandles from subroutines:
+Lexical filehandles also make it easy to pass filehandles info subroutines, or
+return a filehandle from a subroutine--just pass the reference like any other
+reference:
 
     for my $file ( qw(this.conf that.conf) ) {
         my $fin = open_or_throw('<', $file);
@@ -141,31 +98,92 @@ filehandles from subroutines:
         return $h;
     }
 
+=head2 Bareword Filehandles
+
+C<open>'s first argument is normally a reference to a filehandle (a "lexical"
+filehandle), making namespace management easier:
+
+    open my $fh, '<', 'filename' or die "Couldn't open filename: $!";
+    while (<$fh>) {...} # $fh is called "lexical" ("my") or "indirect"
+
+There is another way of specifying filehandles directly--"bareword" filehandles:
+
+    open INFO, '<', 'datafile' or die "Couldn't open datafile: $!";
+    while (<INFO>) {...} # INFO is called "bareword", "direct", or "global"
+
+Since bareword filehandles are global to the current package, two subroutines
+trying to open C<INFILE> will clash. With two functions opening lexical
+filehandles like C<my $infile>, there's no clash and no need to worry about
+future conflicts. Lexical filehandles are also automatically closed when they
+fall out of scope in the same way that lexical variables are garbage-collected.
+
+Bareword filehandles are often used to refer to the standard input (C<*STDIN>),
+output (C<*STDOUT>), and error filehandles (C<*STDERR>), but you can use
+them for any filehandle if you wish.
+
+=head2 Two-Argument Open
+
+There is also an old 2-argument version of C<open>, which lets you put the
+special redirection characters and the filename into the same argument:
+
+    open(my $info, "> $datafile" ) || die "can't create $datafile: $!";
+
+In this case, the filename to open is not a separate argument, so
+you have to worry about C<$datafile> containing characters that might
+influence the open mode, or whitespace in the second argument that wouldn't
+be a problem in the 3-argument version.
+
+Another important thing to notice is that, just as in the shell, any whitespace
+before or after the filename is ignored.  This is good, because you wouldn't
+want these to do different things:
+
+    open my $info,   '<datafile'
+    open my $info,   '< datafile'
+    open my $info,   '<  datafile'
+
+Ignoring surrounding whitespace also helps for when you read a filename in from
+a different file, and forget to trim it before opening:
+
+    $filename = <$info>;         # oops, \n still there
+    open(my $extra, "< $filename") || die "can't open $filename: $!";
+
+This is a feature, not a bug.  Because C<open> mimics the shell in its style of
+using redirection arrows to specify how to open the file, it also does so with
+respect to extra whitespace around the filename itself as well.  For accessing
+files with naughty names, see L<"Dispelling the Dweomer">.
+
+When opening a file, the leading C<< < >> is optional. If omitted, Perl assumes
+that you want to open the file for reading:
+
+    open(my $info, $datafile) || die("can't open $datafile: $!");
+
 =head2 Pipe Opens
 
 In C, when you want to open a file using the standard I/O library,
 you use the C<fopen> function, but when opening a pipe, you use the
 C<popen> function.  But in the shell, you just use a different redirection
-character.  That's also the case for Perl.  The C<open> call 
-remains the same--just its argument differs.  
+character.  That's also the case for Perl.  The C<open> call
+remains the same--just its argument differs.
 
 If the leading character is a pipe symbol, C<open> starts up a new
 command and opens a write-only filehandle leading into that command.
 This lets you write into that handle and have what you write show up on
 that command's standard input.  For example:
 
-    open(PRINTER, "| lpr -Plp1")    || die "can't run lpr: $!";
-    print PRINTER "stuff\n";
-    close(PRINTER)                  || die "can't close lpr: $!";
+    open(my $printer, '| lpr -Plp1') || die "can't run lpr: $!";
+    print $printer "stuff\n";
+    close($printer)                  || die "can't close lpr: $!";
 
 If the trailing character is a pipe, you start up a new command and open a
 read-only filehandle leading out of that command.  This lets whatever that
 command writes to its standard output show up on your handle for reading.
 For example:
 
-    open(NET, "netstat -i -n |")    || die "can't fork netstat: $!";
-    while (<NET>) { }               # do something with input
-    close(NET)                      || die "can't close netstat: $!";
+    open(my $net, 'netstat -i -n |') || die "can't fork netstat: $!";
+    while (<$net>) {
+        # do something with input
+    }
+    close($net)                      || die "can't close netstat: $!";
 
 What happens if you try to open a pipe to or from a non-existent
 command?  If possible, Perl will detect the failure and set C<$!> as
@@ -178,8 +196,8 @@ failure if Perl can't even run the shell.  See L<perlfaq8/"How can I
 capture STDERR from an external command?"> to see how to cope with
 this.  There's also an explanation in L<perlipc>.
 
-If you would like to open a bidirectional pipe, the IPC::Open2
-library will handle this for you.  Check out 
+If you would like to open a bidirectional pipe, the L<IPC::Open2>
+library will handle this for you.  Check out
 L<perlipc/"Bidirectional Communication with Another Process">
 
 perl-5.6.x introduced a version of piped open that executes a process
@@ -220,7 +238,7 @@ access the standard output.
 If minus can be used as the default input or default output, what happens
 if you open a pipe into or out of minus?  What's the default command it
 would run?  The same script as you're currently running!  This is actually
-a stealth C<fork> hidden inside an C<open> call.  See 
+a stealth C<fork> hidden inside an C<open> call.  See
 L<perlipc/"Safe Pipe Opens"> for details.
 
 =head2 Mixing Reads and Writes
@@ -233,13 +251,13 @@ existing one.  On the other hand, using a greater-than always clobbers
 if there isn't an old one.  Adding a "+" for read-write doesn't affect
 whether it only works on existing files or always clobbers existing ones.
 
-    open(WTMP, "+< /usr/adm/wtmp") 
+    open(my $wtmp, '+< /usr/adm/wtmp')
         || die "can't open /usr/adm/wtmp: $!";
 
-    open(SCREEN, "+> lkscreen")
+    open(my $screen, '+> lkscreen')
         || die "can't open lkscreen: $!";
 
-    open(LOGFILE, "+>> /var/log/applog")
+    open($logfile, '+>> /var/log/applog')
         || die "can't open /var/log/applog: $!";
 
 The first one won't create a new file, and the second one will always
@@ -262,14 +280,14 @@ on the end:
     $ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]
 
 This is a short cut for some renaming games that are really
-the best way to update textfiles.  See the second question in 
+the best way to update textfiles.  See the second question in
 L<perlfaq5> for more details.
 
-=head2 Filters 
+=head2 Filters
 
 One of the most common uses for C<open> is one you never
 even notice.  When you process the ARGV filehandle using
-C<< <ARGV> >>, Perl actually does an implicit open 
+C<< <ARGV> >>, Perl actually does an implicit open
 on each file in @ARGV.  Thus a program called like this:
 
     $ myprogram file1 file2 file3
@@ -279,7 +297,7 @@ using a construct no more complex than:
 
     while (<>) {
         # do something with $_
-    } 
+    }
 
 If @ARGV is empty when the loop first begins, Perl pretends you've opened
 up minus, that is, the standard input.  In fact, $ARGV, the currently
@@ -294,17 +312,17 @@ simple ones by hand, the Getopts modules are good for this:
     use Getopt::Std;
 
     # -v, -D, -o ARG, sets $opt_v, $opt_D, $opt_o
-    getopts("vDo:");            
+    getopts('vDo:');            
 
     # -v, -D, -o ARG, sets $args{v}, $args{D}, $args{o}
-    getopts("vDo:", \%args);    
+    getopts('vDo:', \%args);    
 
 Or the standard Getopt::Long module to permit named arguments:
 
     use Getopt::Long;
-    GetOptions( "verbose"  => \$verbose,        # --verbose
-                "Debug"    => \$debug,          # --Debug
-                "output=s" => \$output );       
+    GetOptions( 'verbose'  => \$verbose,        # --verbose
+                'Debug'    => \$debug,          # --Debug
+                'output=s' => \$output );       
 	    # --output=somestring or --output somestring
 
 Another reason for preprocessing arguments is to make an empty
@@ -329,7 +347,7 @@ Here's an example:
                     ? '< /etc/passwd'
                     : 'ypcat passwd |';
 
-    open(PWD, $pwdinfo)                 
+    open(my $pwd, $pwdinfo)
                 or die "can't open $pwdinfo: $!";
 
 This sort of thing also comes into play in filter processing.  Because
@@ -367,7 +385,7 @@ If you want the convenience of the shell, then Perl's C<open> is
 definitely the way to go.  On the other hand, if you want finer precision
 than C's simplistic fopen(3S) provides you should look to Perl's
 C<sysopen>, which is a direct hook into the open(2) system call.
-That does mean it's a bit more involved, but that's the price of 
+That does mean it's a bit more involved, but that's the price of
 precision.
 
 C<sysopen> takes 3 (or 4) arguments.
@@ -413,24 +431,24 @@ but you'll get the idea.
 
 To open a file for reading:
 
-    open(FH, "< $path");
-    sysopen(FH, $path, O_RDONLY);
+    open(my $fh, "< $path");
+    sysopen(my $fh, $path, O_RDONLY);
 
 To open a file for writing, creating a new file if needed or else truncating
 an old file:
 
-    open(FH, "> $path");
-    sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT);
+    open(my $fh, "> $path");
+    sysopen(my $fh, $path, O_WRONLY | O_TRUNC | O_CREAT);
 
 To open a file for appending, creating one if necessary:
 
-    open(FH, ">> $path");
-    sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT);
+    open(my $fh, ">> $path");
+    sysopen(my $fh, $path, O_WRONLY | O_APPEND | O_CREAT);
 
 To open a file for update, where the file must already exist:
 
-    open(FH, "+< $path");
-    sysopen(FH, $path, O_RDWR);
+    open(my $fh, "+< $path");
+    sysopen(my $fh, $path, O_RDWR);
 
 And here are things you can do with C<sysopen> that you cannot do with
 a regular C<open>.  As you'll see, it's just a matter of controlling the
@@ -439,23 +457,23 @@ flags in the third argument.
 To open a file for writing, creating a new file which must not previously
 exist:
 
-    sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT);
+    sysopen(my $fh, $path, O_WRONLY | O_EXCL | O_CREAT);
 
 To open a file for appending, where that file must already exist:
 
-    sysopen(FH, $path, O_WRONLY | O_APPEND);
+    sysopen(my $fh, $path, O_WRONLY | O_APPEND);
 
 To open a file for update, creating a new file if necessary:
 
-    sysopen(FH, $path, O_RDWR | O_CREAT);
+    sysopen(my $fh, $path, O_RDWR | O_CREAT);
 
 To open a file for update, where that file must not already exist:
 
-    sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT);
+    sysopen(my $fh, $path, O_RDWR | O_EXCL | O_CREAT);
 
 To open a file without blocking, creating one if necessary:
 
-    sysopen(FH, $path, O_WRONLY | O_NONBLOCK | O_CREAT);
+    sysopen(my $fh, $path, O_WRONLY | O_NONBLOCK | O_CREAT);
 
 =head2 Permissions E<agrave> la mode
 
@@ -558,7 +576,7 @@ filename that starts with whitespace.  Trailing whitespace is protected
 by appending an ASCII NUL byte (C<"\0">) at the end of the string.
 
     $file =~ s#^(\s)#./$1#;
-    open(FH, "< $file\0")   || die "can't open $file: $!";
+    open(my $fh, "< $file\0")   || die "can't open $file: $!";
 
 This assumes, of course, that your system considers dot the current
 working directory, slash the directory separator, and disallows ASCII
@@ -571,16 +589,16 @@ use a slash.  Maybe C<sysopen> isn't such a bad idea after all.
 If you want to use C<< <ARGV> >> processing in a totally boring
 and non-magical way, you could do this first:
 
-    #   "Sam sat on the ground and put his head in his hands.  
-    #   'I wish I had never come here, and I don't want to see 
+    #   "Sam sat on the ground and put his head in his hands.
+    #   'I wish I had never come here, and I don't want to see
     #   no more magic,' he said, and fell silent."
-    for (@ARGV) { 
+    for (@ARGV) {
         s#^([^./])#./$1#;
         $_ .= "\0";
-    } 
-    while (<>) {  
+    }
+    while (<>) {
         # now process $_
-    } 
+    }
 
 But be warned that users will not appreciate being unable to use "-"
 to mean standard input, per the standard convention.
@@ -601,26 +619,32 @@ temporarily, then all you have to do is this:
     open($path, "< $path") || die "can't open $path: $!";
     while (<$path>) {
         # whatever
-    } 
+    }
 
 Since you're using the pathname of the file as its handle,
 you'll get warnings more like
 
     Some warning at scriptname line 29, </etc/motd> line 7.
 
+A better alternative is to use the L<autodie> pragma, which is included
+in the Perl core distribution as of v5.10.1 (and can be installed as far
+back as Perl 5.8). Autodie makes C<open> throw an exception object that
+provides excellent error messages.
+
 =head2 Single Argument Open
 
-Remember how we said that Perl's open took two arguments?  That was a
-passive prevarication.  You see, it can also take just one argument.
-If and only if the variable is a global variable, not a lexical, you
-can pass C<open> just one argument, the filehandle, and it will 
-get the path from the global scalar variable of the same name.
+Remember how we said that Perl's open took three or two arguments?
+That was a passive prevarication.  You see, it can also take just
+one argument. If and only if the variable is a global variable,
+not a lexical, you can pass C<open> just one argument, the filehandle,
+and it will get the path from the global scalar variable of the same
+name:
 
     $FILE = "/etc/motd";
     open FILE or die "can't open $FILE: $!";
     while (<FILE>) {
         # whatever
-    } 
+    }
 
 Why is this here?  Someone has to cater to the hysterical porpoises.
 It's something that's been in Perl since the very beginning, if not
@@ -640,10 +664,10 @@ failure status.
 You don't have to accept the STDIN and STDOUT you were given.  You are
 welcome to reopen them if you'd like.
 
-    open(STDIN, "< datafile")
+    open(STDIN, '< datafile')
 	|| die "can't open datafile: $!";
 
-    open(STDOUT, "> output")
+    open(STDOUT, '> output')
 	|| die "can't open output: $!";
 
 And then these can be accessed directly or passed on to subprocesses.
@@ -652,9 +676,8 @@ with those redirections from the command line.
 
 It's probably more interesting to connect these to pipes.  For example:
 
-    $pager = $ENV{PAGER} || "(less || more)";
-    open(STDOUT, "| $pager")
-	|| die "can't fork a pager: $!";
+    $pager = $ENV{PAGER} || '(less || more)';
+    open(STDOUT, "| $pager") || die "can't fork a pager: $!";
 
 This makes it appear as though your program were called with its stdout
 already piped into your pager.  You can also use this kind of thing
@@ -665,18 +688,18 @@ just in a different process:
     head(100);
     while (<>) {
         print;
-    } 
+    }
 
     sub head {
         my $lines = shift || 20;
-        return if $pid = open(STDOUT, "|-");       # return if parent
+        return if $pid = open(STDOUT, '|-');       # return if parent
         die "cannot fork: $!" unless defined $pid;
         while (<STDIN>) {
             last if --$lines < 0;
             print;
-        } 
+        }
         exit;
-    } 
+    }
 
 This technique can be applied to repeatedly push as many filters on your
 output stream as you wish.
@@ -694,7 +717,7 @@ just in case.
 
     if (-l $file || ! -f _) {
         print "$file is not a plain file\n";
-    } 
+    }
 
 What other kinds of files are there than, well, files?  Directories,
 symbolic links, named pipes, Unix-domain sockets, and block and character
@@ -704,14 +727,14 @@ Not all plain files are text files.  That's why there are separate C<-f>
 and C<-T> file tests.
 
 To open a directory, you should use the C<opendir> function, then
-process it with C<readdir>, carefully restoring the directory 
+process it with C<readdir>, carefully restoring the directory
 name if necessary:
 
-    opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
-    while (defined($file = readdir(DIR))) {
+    opendir(my $dir, $dirname) or die "can't opendir $dirname: $!";
+    while (defined($file = readdir($dir))) {
         # do something with "$dirname/$file"
     }
-    closedir(DIR);
+    closedir($dir);
 
 If you want to process directories recursively, it's better to use the
 File::Find module.  For example, this prints out all files recursively
@@ -734,8 +757,8 @@ C<readlink> is called for:
             print "$file points to $whither\n";
         } else {
             print "$file points nowhere: $!\n";
-        } 
-    } 
+        }
+    }
 
 =head2 Opening Named Pipes
 
@@ -767,9 +790,9 @@ With descriptors that you haven't opened using C<sysopen>, such as
 sockets, you can set them to be non-blocking using C<fcntl>:
 
     use Fcntl;
-    my $old_flags = fcntl($handle, F_GETFL, 0) 
+    my $old_flags = fcntl($handle, F_GETFL, 0)
         or die "can't get flags: $!";
-    fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK) 
+    fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK)
         or die "can't set non blocking: $!";
 
 Rather than losing yourself in a morass of twisting, turning C<ioctl>s,
@@ -784,8 +807,8 @@ Check out Term::ReadKey and Term::ReadLine.
 =head2 Opening Sockets
 
 What else can you open?  To open a connection using sockets, you won't use
-one of Perl's two open functions.  See 
-L<perlipc/"Sockets: Client/Server Communication"> for that.  Here's an 
+one of Perl's two open functions.  See
+L<perlipc/"Sockets: Client/Server Communication"> for that.  Here's an
 example.  Once you have it, you can use FH as a bidirectional filehandle.
 
     use IO::Socket;
@@ -814,7 +837,7 @@ handles before doing regular I/O on them:
 
     binmode(STDIN);
     binmode(STDOUT);
-    while (<STDIN>) { print } 
+    while (<STDIN>) { print }
 
 Passing C<sysopen> a non-standard flag option will also open the file in
 binary mode on those systems that support it.  This is the equivalent of
@@ -834,7 +857,7 @@ sneaky data mutilation behind your back.
 
     while (sysread(WHENCE, $buf, 1024)) {
         syswrite(WHITHER, $buf, length($buf));
-    } 
+    }
 
 Depending on the vicissitudes of your runtime system, even these calls
 may need C<binmode> or C<O_BINARY> first.  Systems known to be free of
@@ -893,10 +916,10 @@ if you're going to be blocking:
     use Fcntl qw(:DEFAULT :flock);
     open(FH, "< filename")  or die "can't open filename: $!";
     unless (flock(FH, LOCK_SH | LOCK_NB)) {
-	$| = 1;
-	print "Waiting for lock...";
-	flock(FH, LOCK_SH)  or die "can't lock filename: $!";
-	print "got it.\n"
+	    $| = 1;
+	    print "Waiting for lock...";
+	    flock(FH, LOCK_SH)  or die "can't lock filename: $!";
+	    print "got it.\n";
     } 
     # now read from FH
 
@@ -974,7 +997,7 @@ The two-argument form of C<binmode> is being used, for example
 For more detailed discussion about PerlIO see L<PerlIO>;
 for more detailed discussion about Unicode and I/O see L<perluniintro>.
 
-=head1 SEE ALSO 
+=head1 SEE ALSO
 
 The C<open> and C<sysopen> functions in perlfunc(1);
 the system open(2), dup(2), fopen(3), and fdopen(3) manpages;
@@ -982,7 +1005,7 @@ the POSIX documentation.
 
 =head1 AUTHOR and COPYRIGHT
 
-Copyright 1998 Tom Christiansen.  
+Copyright 1998 Tom Christiansen.
 
 This documentation is free; you can redistribute it and/or modify it
 under the same terms as Perl itself.
-- 
1.6.3.2

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2011

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2011

From doherty@cs.dal.ca

I think the current plan is to completely rewrite the documentation. I
believe the best effort to do so is currently
https://github.com/doherty/perl5-open-tutorial (which should really be
under https://github.com/perl-doc-cats...)

I think rewriting it is probably the only way to get sufficient
agreement for inclusion. Please feel free to help.

-Mike

@p5pRT
Copy link
Author

p5pRT commented Jul 3, 2012

From @doy

Is anyone still working on this? I would still very much like this to
happen, but if it has actually been abandoned, there's probably no
reason to keep this ticket open.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jul 3, 2012

From tchrist@perl.com

"Jesse Luehrs via RT" <perlbug-followup@​perl.org> wrote
  on Tue, 03 Jul 2012 14​:10​:48 PDT​:

Is anyone still working on this? I would still very much like this to
happen, but if it has actually been abandoned, there's probably no
reason to keep this ticket open.

I didn't care for the knee-jerk "Modern® Perl™" revisionist history
approach to opening files.

I'm not in favor of the notion that hiding the regular shell open and
regular filehandles from people is a good idea.

Basically, the spin sucked.

--tom

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @rjbs

* Jesse Luehrs via RT <perlbug-followup@​perl.org> [2012-07-03T17​:10​:48]

Is anyone still working on this? I would still very much like this to
happen, but if it has actually been abandoned, there's probably no
reason to keep this ticket open.

I think this can be closed until there is a new patch.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

@cpansprout - Status changed from 'open' to 'rejected'

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From doherty@cs.dal.ca

On 12-07-03 06​:38 PM, tchrist1 via RT wrote​:

"Jesse Luehrs via RT" <perlbug-followup@​perl.org> wrote
on Tue, 03 Jul 2012 14​:10​:48 PDT​:

Is anyone still working on this? I would still very much like this to
happen, but if it has actually been abandoned, there's probably no
reason to keep this ticket open.

I've been effectively warned off.

I did hear rumours of someone else taking it on, but I haven't seen any
actual work.

I don't see why the ticket should be closed - the tutorial *should* be
modernized, and until that's done, the ticket should stay open. I
appreciate Tom's reluctance to bury the useful items he mentioned, but
that's not an argument to ban revisions to the tutorial, it is an
argument to rewrite it well.

-Mike

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From tchrist@perl.com

I disagree with your "modernize" position.

There is nothing unmodern old-fashioned -- let alone wrong -- with using
named unsigiled unautovivified filehandles and two-argument open for the
type of programs they were designed. It's a dumb witch hunt.

--tom

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @demerphq

On 4 July 2012 16​:25, Tom Christiansen <tchrist@​perl.com> wrote​:

I disagree with your "modernize" position.

There is nothing unmodern old-fashioned -- let alone wrong -- with using
named unsigiled unautovivified filehandles and two-argument open for the
type of programs they were designed. It's a dumb witch hunt.

While I respect your rights with regard to the document in question I
wish to register the fact that I disagree with the point you make
here.

Perl has moved on since you wrote this document. It has grown past the
"hacky sysadmin tool" to the main language used in multi-billion
dollar shops with hundreds of developers. The needs of the community
have moved on too. Neat hacks are no-where near as important as well
trained devs who can be hired by companies like mine. Which is good
for my company, and good for perl devs because we give them jobs.

So it is not a dumb witch hunt.

I'll ask you a question​: how many perl devs are in your shop? What is
the most number of perl devs you have worked with at one time?

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @doy

On Wed, Jul 04, 2012 at 01​:24​:25PM -0600, Tom Christiansen wrote​:

=============
Short story

EITHER​:
#1 Show the courage to formally propose that all these myriad
things you morally disapprove of be RIPPED OUT of Perl once
and for all.
OR ELSE​:
#2 Have the integrity to stop scolding people for the perfectly
legal acts they enjoy in their own bedroom.

==============
Medium story

I am sick and tired of the scolding culture that has grown up
around here. It is stupid, and it is harmful. Make it stop.

The entire PerlCritic disaster has virtually ruined Perl culture,
replacing it with a bunch of busybodied holier-than-thou types.

And for what? For NOTHING, that's for what.

It is not a fun place to be. It is not in the spirit of Perl to
police people's private lives, or their past lives. I hate it.

Please stop with all the judgementalism, *especially* all this
scolding judgementalism that comes unaccompanied by actual
proposals and offers to rip out of Perl whatsoever you hold in
moral contempt. It does more harm than good.

--tom

============
Long story

<snip>

Nobody at all is proposing removing these things from the language. The
only proposal here is changing what new programmers see in the basic
tutorial. Avoiding globals when possible is generally considered to be
good practice in any language, I don't think that's something that's
really going to change at this point.

Now, as for this rant, this sort of thing is at least as
counterproductive as anything the people you're ranting against are
doing. This drives away new programmers, makes p5p a much more
unwelcoming place to be, and generally reflects badly on the Perl
community. These sorts of threads were one of the main reasons that I
avoided participating in p5p for as long as I did, and I know I'm not
the only one.

Perl (pretty desperately) needs to attract new developers to working on
the core, and every time something like this comes up, it's just one
more reason for new people to stay away. Can we please try to stay a bit
more civil?

-doy

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @rjbs

* Tom Christiansen <tchrist@​perl.com> [2012-07-04T15​:24​:25]

I am sick and tired of the scolding culture that has grown up
around here. It is stupid, and it is harmful. Make it stop.

I cannot even begin to express how this paragraph, followed by the rest of the
email, makes me feel. It isn't good.

As far as I know, nobody wants to make these things stop working. Nobody wants
to delete all reference them. Nobody wants to make them issue warnings.

The entire question is whether they should be the first thing a user gets to
when reading the "open" tutorial, and the default for showing off the rest of
"open" in that document.

I don't think anybody here is judging anybody else's private life or expressing
moral contempt. Instead, they're saying, "People are going to learn Perl from
the tutorial documents. Someday I'm going to need to hire more Perl people.
What kind of Perl would I like them to have grown up writing?"

I'll be damned if I'm going to rewrite 43,000 lines of perfectly
functioning Perl code just to appease a meddling bunch of busibodies'
nose-cleaning ethic.

Nobody is saying anybody needs to rewrite a single thing, except maybe the
order and style of presentation of contents in one tutorial.

I'm tired of listening to Pharisees on street corners ranting and raving
about the splinter in others' eyes. Some of us have actual work to do, and
the scold-culture's posturing just gets in the way of that.

Listen to yourself, here, Tom. Then listen to yourself again​:

I am sick and tired of the scolding culture that has grown up
around here. It is stupid, and it is harmful. Make it stop.

I'm done with perl5-porters for today. I'll be back tomorrow.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @Leont

On Wed, Jul 4, 2012 at 10​:24 PM, Tom Christiansen <tchrist@​perl.com> wrote​:

=============
Short story

EITHER​:
#1 Show the courage to formally propose that all these myriad
things you morally disapprove of be RIPPED OUT of Perl once
and for all.
OR ELSE​:
#2 Have the integrity to stop scolding people for the perfectly
legal acts they enjoy in their own bedroom.

==============
Medium story

I am sick and tired of the scolding culture that has grown up
around here. It is stupid, and it is harmful. Make it stop.

The entire PerlCritic disaster has virtually ruined Perl culture,
replacing it with a bunch of busybodied holier-than-thou types.

And for what? For NOTHING, that's for what.

It is not a fun place to be. It is not in the spirit of Perl to
police people's private lives, or their past lives. I hate it.

Please stop with all the judgementalism, *especially* all this
scolding judgementalism that comes unaccompanied by actual
proposals and offers to rip out of Perl whatsoever you hold in
moral contempt. It does more harm than good.

--tom

Tom,

No one is judging you or anyone else for using 2-arg open. No one
scolded you for using package globals as filehandles. I see you're
feeling under attack but I think you're fighting a monster that
doesn't exist.

I can imagine it hurts when people want to rewrite a piece of
documentation that you wrote and are proud of, but taking it
personally doesn't help your cause. By reacting this antagonistically,
you're actively isolating yourself.

A competent perl programmer needs to understand both, I am fairly
certain we all agree on that, the only real discussion here is how

The main point of what most people are trying to say here is that we
should introduce these concepts in a different order than we do now.
It's much easier to explain how 3-arg open works than 2-arg open,
because there's less hidden surprises. Indirect filehandles don't have
the scoping issue that direct filehandles have.

We on p5p all understand such subtle issues, and know when we don't
have to worry about that, but do we really want to bother a newbie
who's just learning perl with that when they're just trying to open a
file?

Leon

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From @doy

Closing this for now, until a new patch is written.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

From [Unknown Contact. See original ticket]

Closing this for now, until a new patch is written.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jul 4, 2012

@doy - Status changed from 'rejected' to 'resolved'

@p5pRT p5pRT closed this as completed Jul 4, 2012
@p5pRT
Copy link
Author

p5pRT commented Jul 5, 2012

From tchrist@perl.com

Leon wrote​:

The main point of what most people are trying to say here is that we
should introduce these concepts in a different order than we do now.
It's much easier to explain how 3-arg open works than 2-arg open,
because there's less hidden surprises. Indirect filehandles don't have
the scoping issue that direct filehandles have.

Fine. I withdraw all objection.

Don't forget to talk about encodings if you're going to do
the full three-arg open thing.

--tom

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant