.. 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] |
Both of those approaches could be used to work around the problem in
the examples I gave so far, but actually the situation is slightly
more complicated:
# foo.pl
for (1..2) {
eval "use bar";
print "attempt $_: ", ($@ || 'success'), "\n";
}
# bar.pm
eval "require baz";
if ($@) {
die "bar will be unavailable because baz didn't load properly.";
}
1;
# baz.pm
use missingdependency;
So adding delete $INC{bar.pm} if $@; to foo.pl isn't
sufficient--I also need to delete baz.pm. This would be easy
if I could modify bar.pm, but I don't want to--bar.pm is a third-party
plugin that was written for earlier versions of foo.pl, and I'd prefer
not to break backwards compatibility for the plugins.
But the following works, without any changes to bar.pm or baz.pm:
# foo.pl
for (1..2) {
my %saveinc = %INC;
eval "use bar";
if ($@) {
for my $package(keys %INC) {
delete $INC{$package} if ! exists $saveinc{$package};
}
}
print "attempt $_: ", ($@ || 'success'), "\n";
}
I think that'll basically do the trick. Maybe I'll also delete the symbol table of the packages I delete from %INC, in case some of them actually loaded successfully, to avoid getting warnings about redefinitions later on. Thanks everyone for all the ideas.
| [reply] [d/l] [select] |
This may fix your immediate problem:
# bar.pm
BEGIN {
eval {
die
}
}
or
# bar.pm
CHECK {
die
}
Be well,
rir | [reply] [d/l] [select] |