blahblahblah has asked for the wisdom of the Perl Monks concerning the following question:

I work on a large cgi application that consists of multiple scripts. To keep the size of each script down, we autoload a lot of general-purpose subs from separate files. I realized last week that we ignore a lot of useful information by not checking $!, so I tried to add a new sub to make checking $! convenient. I ran into a problem, though, where autoloading my sub seemed to reset $!.

I narrowed the problem down to the fact that doing the following wipes out $!:

eval {require "file"};
At first I thought that maybe $! behaves like $@, in that you could count on it being undef if whatever you just did was successful. But that wasn't true: when I replaced my eval line with an unlink of a file that did exist, $! still had the error from the first, unsuccessful unlink ($^E was reset, though).

Does anyone know why the eval{require..} sets $! even though it's successful? Here's a little program that shows what I've tried, independent of autoloading or any other complications of my larger program:

# this sets $! and $^E unlink 'asdfasdfewtwertwevbncvbnmarewrawer'; # This wipes them both out. # Note that test.pl contains only "1;", and $@ is undef afterwards. eval {require "test.pl"}; print "\$\@: $@\n" if $@; # If I comment the eval line out, this prints: # error?: last system error: No such file or directory # (error number: 2) (extended error info: The system # cannot find the file specified # Otherwise it just prints: # error? print "error?: ", &CheckLastSystemError(), "\n"; # Here's my sub. Feel free to add suggestions for it also if you have + any. sub CheckLastSystemError { my @message; # check the string value push @message, "$!" if $!; # we could check $^E here, too... # check the number value my $numericTest = 0 + $!; # force numeric context push @message, "(error number: $numericTest)" if $numericTest; # $^E is sometimes just the same as $! push @message, "(extended error info: $^E" if ($^E && $^E ne $!); if (scalar @message) { # combine @message into a string and return it return "last system error: @message"; } else { return undef; } }
This is not a big dilemma for me since I've worked around it for now by putting my sub into our main library file which always gets required. It is something I'd like to figure out if I could, though, since some of our error handling subs are also autoloaded and might potentially wipe out $! themselves.

Replies are listed 'Best First'.
Re: why would a successful eval of a require reset $!?
by tall_man (Parson) on Feb 11, 2003 at 04:12 UTC
    There's a long-standing rule in Unix that one should never check the value of errno except immediately following a failed system call -- otherwise there are no guarantees about its value. Since $! is a magic alias for errno, the same rules apply. That's basically what perlvar says about it, too:

    If used in a numeric context, yields the current value of errno, with all the usual caveats. (This means that you shouldn't depend on the value of $! to be anything in particular unless you've gotten a specific error return indicating a system error.)

Re: why would a successful eval of a require reset $!?
by chromatic (Archbishop) on Feb 11, 2003 at 17:01 UTC

    localize $! if you don't want to lose it.