This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Replace default filehandle/select with $DEFOUT, $DEFERR, $DEFIN =head1 VERSION Maintainer: Nathan Wiger <[EMAIL PROTECTED]> Date: 17 Aug 2000 Last-Modified: 13 Sep 2000 Mailing List: [EMAIL PROTECTED] Number: 129 Version: 2 Status: Frozen =head1 ABSTRACT A basic Perl 5 implementation can be found as IO::Default at http://www.perl.com/CPAN/authors/id/N/NW/NWIGER/IO-Default-1.03.tar.gz The concept of a "default filehandle" is nebulous. Many users can't get their heads around it, and even if they can, it is still kind of mysterious. This proposes that the "default filehandle" and 1-arg select be dropped from Perl 6 and replaced with the variable C<$DEFOUT>, the Default Output handle. Whatever this variable contains will be what is printed to by default. This will make default output consistent with the C<fileobject> approach and also other Perl special variables. In addition, this RFC proposes the addition of two new variables, C<$DEFERR> and C<$DEFIN>, the Default Error and Default Input handles. These can be used to redirect default error output and default input, for added flexibility. =head1 NOTES ON FREEZE Some discussion, particularly by Jon Ericson, was recorded on this RFC. Most of it boiled down to clarifications of issues. Jon questioned the usefulness of C<$DEFERR>, but I think it serves a very useful purpose since it allows you to redirect warnings (which would be directed to C<$DEFERR>) without affecting statements that print to C<$STDERR> explicitly. There is also very nice symmetry between the C<DEF*> default handles and the C<STD*> standard handles. =head1 DESCRIPTION =head2 $DEFOUT Currently, the "default filehandle" ("DF" to save typing) is hidden. It can only be accessed or changed via the C<select> function. With the advent of full-featured B<fileobjects>, having a special DF is unnecessary. Instead, we simply make a variable, called C<$DEFOUT>, which is where unspecified output is sent. Changing the DF is done through simple variable assignment. Below are some examples of Perl 5 versus Perl 6 syntax: Perl 5 Perl 6 ----------------------- -------------------------- select FILE; $DEFOUT = $FILE; $oldh = select; $oldh = $DEFOUT; $oldh = select FILE; $oldh = $DEFOUT; $DEFOUT = $FILE; $| = 1 $DEFOUT->autoflush(1); # or: autoflush $DEFOUT; # ? What advantages besides a new syntax are there? Several: 1. The rule is easier. No DF, just "everything goes to $DEFOUT by default". Changing this is done by simple assignment. 2. It's less hidden. Most everything else in Perl is handled in variables such as @INC, %ENV, and so forth. This makes filehandles that much easier. 3. Access to object methods is available directly on the current filehandle object via $DEFOUT->method, eliminating the need for $|, $/, $\, and so on.[1] 4. No more 1-arg select vs. 4-arg select confusion. Whatever object C<$DEFOUT> contains is what default output goes to and what the object methods work on. There is no mysterious hidden DF. C<$DEFOUT> works just like other variables. =head2 $DEFERR The new C<$DEFERR> variable can be used to easily redirect error output as well, something you often want to do if you're not attached to a tty. However, having a script that runs easily in both environments is tricky in Perl 5: if ( $have_a_tty ) { print STDERR "Warning: Bad stuff\n"; } else { print ERRORLOG "Warning: Bad stuff\n"; } You have to put checks similar to this for many functions and different situations. Plus, it doesn't catch C<carp> or C<die> calls embedded in modules, meaning that you will always lose some important error output. With C<$DEFERR>, all error functions are set to act on it instead of C<$STDERR> by default. So, the Perl 6 version of the above is replaced by a single simple line of code at the top of your main program: $DEFERR = $ERRORLOG unless $have_a_tty; Presto, all error-related functions now redirect to your error log automatically. All through simple assignment. As Jon Ericson pointed out, this can be accomplished in a similar vein currently by reopening STDERR onto another file, or by using typeglob aliases to other open filehandles. However, it does not allow you to mix calls to files and STDERR like you can with files and STDOUT. Using $DEFERR allows you to do so if you have functions that you want to explicitly print to C<$STDERR>: warn "Badness!"; # goes to $DEFERR print $STDERR "Badness!" # explicitly to $STDERR This is not easy to do in Perl 5.[2] This is quite useful if, for example, you want a cron job to log all error either to the screen or log files but always print out the same message at the end: $DEFERR = $ERRORLOG unless $have_a_tty; # ... warn "Bad stuff: $!"; # to $DEFERR # ... carp "This too: $!"; # ditto # ... if ( $really_bad ) { print $STDERR "Fatal error! Check the logfiles!\n"; exit 1; } That way you'd get a cron-generated message (perhaps to your pager) that was brief, while the code could still send other errors to either the screen or logfile automatically. =head2 $DEFIN The new C<$DEFIN> accomplishes a similar thing, but with input. Currently, the special <> filehandle iterates through the command-line files stored in C<@ARGV>. You can also use it to open C<STDIN>, but only if C<@ARGV> is empty (it unshifts '-' onto C<@ARGV>). However, <> is potentially more useful as a default input filehandle, much like a simple "print" uses $_ for its default output: @data = <>; # read from $DEFIN The new C<$DEFIN> variable becomes what is read from when <> is used. It should point to C<$STDIN> by default. This allows greater flexibility, more consistency with operators like print, and doesn't require us to reopen filehandles to get to different input sources: # Figure out our input source based on what's open $DEFIN = $infile || $instream || $STDIN; @data = <>; This allows valuable compartmentalization of code. The simple <> construct is now a synonym for C<$DEFIN>. This means that you can place something like the C<@data = ><> line in a module, and allow the top-level code to change the data source based on a simple assignment. You no longer have to pass filehandles into functions or do complex C<tie> manuevers to gain this ability. Plus, with C<$DEFIN>, if you have a routine that must read from C<$STDIN>, you can still do so easily by explicitly saying: $yes_or_no = <$STDIN>; # explicitly from $STDIN @data = <>; # read from $DEFIN To retain the special behavior currently with <>, it is recommended that Perl 6 require explicit use of C<$ARGV>: while (<$ARGV>) { } # iterate through @ARGV This has the benefit that it makes it more obvious that we're iterating through C<@ARGV>. It also means that you can use <> to grab C<STDIN> while retaining the values in <@ARGV>, which is not possible currently. =head2 Naming The naming of the variables was chosen to make them consistent with the Standard IO handles C<$STDIN>, C<$STDOUT>, and C<$STDERR>. =head1 IMPLEMENTATION Remove 1-arg C<select>. Make sure p52p6 translates C<select> to the new syntax. Create C<$DEFOUT> variable and reset output functions to act on C<$DEFOUT> instead of the default filehandle. C<$DEFOUT> should point to the system's stdout by default, just like the default filehandle does currently. Add C<$DEFERR> variable and reset error functions (such as warn and die) to print to C<$DEFERR> instead of C<STDERR>. C<$DEFERR> should point to the system's stderr by default, just like STDERR. Add C<$DEFIN> and change <> and other default input to work on C<$DEFIN>. C<$DEFIN> should point to the system's stdin by default. A basic Perl 5 implementation can be found as IO::Default at http://www.perl.com/CPAN/authors/id/N/NW/NWIGER/IO-Default-1.03.tar.gz =head1 MIGRATION The 1-arg C<select> syntax would have to be translated to something like: $DEFOUT = $FILE; # was select(FILE); Since the only other thing that would really change would be the meaning of <> in loops, p52p6 would have to translate while(<>) to: while (<$ARGV>) { } However, when used outside of a loop, like so: @file = <>; No translation would have to take place since the usage would likely be a shortcut to C<STDIN> (which would be retained since <> == C<$DEFIN> == C<$STDIN> by default). =head1 NOTES [1] This RFC does not take a firm stance on eliminating $|, $/, $\, and friends. However, this approach to handling default input and output does mean they are no longer needed. I do think they should go, but this RFC does not require it. [2] It is possible in a way, but you can't print to STDERR explicitly, and you have to use a series of open calls. Better to just send it to the default error handle, whatever that may contain. =head1 REFERENCES RFC 14: Modify open() to support FileObjects and Extensibility RFC 30: STDIN, STDOUT, and STDERR should be renamed http://www.mail-archive.com/perl6-language-io%40perl.org/msg00182.html http://www.mail-archive.com/perl6-language-io%40perl.org/msg00228.html