Reputation: 4465
My Perl program contains two blocks similar to this one:
open my $file, '>', $filename or do{
print "Failed to open file\nFile not saved\n";
return;
}
When I run it I get this:
"my" variable @lines masks earlier declaration in same scope at myfile.pl line 43.
"my" variable @args masks earlier declaration in same scope at myfile.pl line 43.
"my" variable @args masks earlier declaration in same statement at myfile.pl line 43.
"my" variable @args masks earlier declaration in same scope at myfile.pl line 47.
syntax error at myfile.pl line 19, near "$i ("
Global symbol "$i" requires explicit package name at myfile.pl line 20.
Global symbol "$file" requires explicit package name at myfile.pl line 21.
Global symbol "$i" requires explicit package name at myfile.pl line 21.
Global symbol "$file" requires explicit package name at myfile.pl line 23.
syntax error at myfile.pl line 24, near "}"
syntax error at myfile.pl line 35, near "}"
syntax error at myfile.pl line 44, near "}"
syntax error at myfile.pl line 54, near "}"
Can't use global @_ in "my" at myfile.pl line 57, near ", $_"
myfile.pl has too many errors.
But when I replace it with this:
do{
print "Failed to open file\nFile not saved\n";
return;
}unless open my $file, '>', $filename;
All the errors instantly disappear and the program runs fine. I have use strict
and use warnings
.
Does anyone understand why this is happening? Is there something wrong with my parentheses or something? Changing the spacing in the open
function does nothing.
EDIT: I have replaced the print
statements with warn
.
Upvotes: 1
Views: 227
Reputation: 107030
I take it this has something to do with a subroutine. Otherwise, why do you have a return
?
Use a standard if
statement. This way, it's just clearer what the program is doing:
my $file;
if ( not open $file, ">", $filename ) {
warn qq(Failed to open file "$filename"\nFile not saved\n);
return;
}
Notice:
$file
outside of my if
. Otherwise, $file
becomes undefined outside of my if
. Probably not what you want. (And is what is causing your problems).warn
. This prints to STDERR
rather than STDOUT
. It also alerts a developer skimming through your code that this is some sort of error message and might be important to note.The latest style programming style is to lets subroutines die on errors. This means you can simply do this in your subroutine:
open my $fh, ">", $filename
or die qq(Can't open "$filename"\n);
Now, if the developer doesn't want the program to die, the developer now has to actively handle the error with an eval
:
my $fh;
eval {
$fh = openlog ( $filename );
};
if ( $@ ) {
warn qq(Can't open log file "$filename". No log will be written);
}
This is the way exception handling programming languages like Python and Java force developers to face up to errors. Otherwise, a developer could simply assume that the subroutine worked. In Perl, you see stuff like this all the time:
send_email( email_address( $user ), $message );
Um... Did email_address()
actually return an email address before the program attempts to send out an email?
Upvotes: 0
Reputation: 126722
In the first case
open ( my $file, '>', $filename ) or do {
print "Failed to open file\nFile not saved\n";
return;
}
the my $file
is in scope outside the do
block, whereas in
do {
print "Failed to open file\nFile not saved\n";
return;
} unless open my $file, '>', $filename;
it is local to the block. Note that that also means you can't use $file
to write to after you have opened it as it is immediately closed again.
You can
Use different identifiers for each file handle
Omit the my
from all open
calls after the first
Enclose each open
, and the subsequent file operations, inside its own block, like this
{
open( my $file, '>', $filename ) or do{
print "Failed to open file\nFile not saved\n";
return;
};
# Write to $file
}
Upvotes: 3