I'll build up
Code:
open( local *OUTPUT, '>', ++$output_file )
from bits.
Start with the straight open:
Code:
open( OUTPUT, ">$outputfile" )
According to
perlopen, there is an equivalent three argument form:
Code:
open( OUTPUT, '>', $outputfile )
This is slightly more efficient (we're not building a new string from '>' and $outputfile) but, more importantly, it lets us play games with $outputfile.
Before we get there, let's look quickly at localisation. local() gets bad press because it doesn't do what people familiar with other languages expect - [tt]my()[/tt] is usually what's required. [tt]my()[/tt], however, cannot be used on filehandles and, as it happens, [tt]local()[/tt] both restricts the accessibility and the life of the filehandle to the enclosing block. It's not quite lexicalisation (a la my()) but it's prefereable to global filehandles. The catch is that you have to localise the entire typeglob (*OUTPUT) rather than just the filehandle.
Digression: a typeglob is how perl keeps track of all gloabl things with the same name, so *OUTPUT refers to the scalar $OUTPUT, the array @OUTPUT, the hash %OUTPUT, the code &OUTPUT as well as the filehandle OUTPUT. Localising the typeglob localises all of these things. If you stick to the handy convention of using all uppercase for filehandles (and for nothing else) then this won't bite you as you won't have a $OUTPUT to worry about.
To explicitly declare a filehandle's typeglob as local, we'd say
Code:
while( [i]something[/i] ) {
local *OUTPUT;
open( OUTPUT, ...
....
last if [i]condition[/i]; # OUTPUT closed here if condition is true
....
} # OUTPUT closed here otherwise
This means that, amongst other things, the filehandle OUTPUT is more protected from possible interference from the rest of your code and, as a bonus, it automatically closes as control leaves the enclosing block.
As a shorthand for
Code:
local *OUTPUT;
open( OUTPUT, ...
you can say
just as you would usually condense
Code:
my $i;
foreach $i (@list) {
...
to
Code:
foreach my $i (@list) {
...
That gets our example to
Code:
open( local *OUTPUT, '>', $outputfile )
Now lets look at $outputfile and that wonderful ++ operator. According to
perlop,
If you increment a variable that is numeric, or that has ever been used in a numeric context, you get a normal increment. If, however, the variable has been used in only string contexts since it was set, and has a value that is not the empty string and matches the pattern /^[a-zA-Z]*[0-9]*\z/ , the increment is done as a string, preserving each character within its range, with carry:
Code:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
print ++($foo = 'Az'); # prints 'Ba'
print ++($foo = 'zz'); # prints 'aaa'
undef is always treated as numeric, and in particular is changed to 0 before incrementing (so that a post-increment of an undef value will return 0 rather than undef).
The auto-decrement operator is not magical.
Because we split off the '>' into a separate argument to open, it's now easy to apply the magical pre- or post-increment operator to $outputfile:
Code:
open( local *OUTPUT, '>', ++$output_file )
So we've now got more protected filehandles, automatic filehandle closure (however we exit the loop) and automatic filename generation in one line. I think it's quite legible in the circumstances - more so if it becomes part of your normal toolkit.
HTH,
fish
["]As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.["]
--Maur