Is this a perl bug, or is there some justification for the behavior?
perldoc -f require :
... demands that a library file be included if it hasn't
already been included. The file is included via the do-FILE mechanism, which is essentially just a variety of "eval" ...
The second time require does not have to include library (again) thus:
#test.pl
for (1..2) {
eval "require bar";
print "attempt $_: ", ($@ ? "nok - $@" : "ok"), "\n";
}
#bar.pm
use Carp;
croak "loaded$/"
# STDOUT:
attempt 1: nok - loaded
require bar.pm called at (eval 1) line 3
eval 'require bar
;' called at test.pl line 3
Compilation failed in require at (eval 1) line 3.
attempt 2: ok
What's the correct way to load a module if and only if it hasn't already been loaded successfully?
If a module cannot be loaded successfully the fisrt time why should we believe that it will be loaded successfully the second time?
| [reply] [d/l] |
.. demands that a library file be included if it hasn't already been included. The file is included via the do-FILE mechanism, which is essentially just a variety of "eval"
I can't find a definition of exactly what "included" means, but you
seem to be saying that if the file is found, and is readable, and an
attempt to compile and load it is made, then the file is considered to
have been "included," even if the compilation or loading fails. But
in fact this is not the case. Here's a pair of examples that shows
the inconsistency:
#foo.pl
for (1..2) {
eval "use bar";
print "attempt $_: ", ($@ ? 'fail' : 'succeed'), "\n";
}
#bar.pm
0
#stdout
attempt 1: fail
attempt 2: fail
# now change bar.pm to the following:
die
#stdout
attempt 1: fail
attempt 2: succeed
In the first case, perl attempts to load bar.pm twice, but in the
second case it only tries once. So apparently if a module loads
successfully but returns 0, it has not been "included," but if it fails
to load then it has been "included?"
Incidentally, while preparing this example I discovered a falsehood in
the documentation for "use." It says that use bar is
exactly equivalent to BEGIN { require bar; import bar; }
but if you substitute the latter for the former in the example, the
results are different.
FWIW, here's my situation. My application has a large number of
modules, only a few of which are used by any given user. Currently
they're all require'd at startup, with the require inside an eval so
that if a module fails to load, the user is notified that it is
unavailable, but he can continue to use the other modules. To reduce
startup time, I want to postpone loading each module until the user
explicitly activates it by clicking on it in the gui. If the user
clicks on a module and it fails to load, he gets an error dialog. But
if he's obstinate enough to click on it a second time, currently the
application acts as if the module loaded successfully, even though it
really didn't. I'm going to have to keep track explicitly of which
modules the application has already attempted to load, and avoid
trying any module twice. First of all, this is kind of annoying
because I thought this was exactly the kind of thing that "require"
was supposed to take care of. Secondly, it means that if the user
fixes whatever condition caused the module not to load the first time
(maybe he installed a dependency, fixed a configuration file,
whatever... these modules are third-party plugins, out of my
application's control) he's going to have to restart the application,
which ought to be unnecessary.
Thanks for your help.
| [reply] [d/l] [select] |
I can't find a definition of exactly what "included" means, but you seem to be saying that if the file is found, and is readable, and an attempt to compile and load it is made, then the file is considered to have been "included," even if the compilation or loading fails. But in fact this is not the case.
No, he doesn't say that. You need to read perlfunc
| [reply] |
| [reply] |
This may fix your immediate problem:
# bar.pm
BEGIN {
eval {
die
}
}
or
# bar.pm
CHECK {
die
}
Be well,
rir | [reply] [d/l] [select] |
I think that loading the module with "do" instead of "require" will give you the control you're looking for. I've never tried it, but from "perldoc -f do" it looks pretty simple:
do EXPR Uses the value of EXPR as a filename and executes the contents
of the file as a Perl script. Its primary use is to include
subroutines from a Perl subroutine library.
do 'stat.pl';
is just like
eval `cat stat.pl`;
except that it's more efficient and concise, keeps track of the
current filename for error messages, searches the @INC
libraries, and updates %INC if the file is found. See
"Predefined Names" in perlvar for these variables. It also
differs in that code evaluated with "do FILENAME" cannot see
lexicals in the enclosing scope; "eval STRING" does. It's the
same, however, in that it does reparse the file every time you
call it, so you probably don't want to do this inside a loop.
If "do" cannot read the file, it returns undef and sets $! to
the error. If "do" can read the file but cannot compile it, it
returns undef and sets an error message in $@. If the file is
successfully compiled, "do" returns the value of the last
expression evaluated.
Note that inclusion of library modules is better done with the
"use" and "require" operators, which also do automatic error
checking and raise an exception if there's a problem.
You might like to use "do" to read in a program configuration
file. Manual error checking can be done this way:
# read in config files: system first, then user
for $file ("/share/prog/defaults.rc",
"$ENV{HOME}/.someprogrc")
{
unless ($return = do $file) {
warn "couldn't parse $file: $@" if $@;
warn "couldn't do $file: $!" unless defined $return;
warn "couldn't run $file" unless $return;
}
}
Just out of curiosity, why would the second attempt work? Are you modifying the file before retrying? Is it a configuration file or something?
| [reply] |
This is a perl bug, already fixed in the current development track. In fact it was fixed early enough to get into the perl-5.9.1 interim release, so I'm not sure why it hasn't made it into a 5.8.x maintenance release - maybe the potential for backward compatibility problems seemed too high.
Hugo
| [reply] |