Arc676
Arc676

Reputation: 4465

Seemingly Random Perl Errors

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

Answers (2)

David W.
David W.

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:

  • I have to define $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).
  • I also use 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

Borodin
Borodin

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

Related Questions