Someone has an idea to use array variable in place of array (list) literal, in the use
function statement, like:
my @list = qw(foo zoo);
use Module @list;
instead of
use Module qw(foo zoo);
So she writes e.g.:
my @consts = qw(PF_INET PF_INET6);
use Socket @consts;
printf "%d, %d\n", PF_INET, PF_INET6;
which seemingly works as expected:
2, 10
Then she is doing it with some other module, e.g. Time::HiRes
. Instead of
use Time::HiRes qw(CLOCK_REALTIME CLOCK_MONOTONIC);
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
0, 1
she does:
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
use Time::HiRes @consts;
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
0, 0
It suddenly does not work, like it worked with Socket
module!
Something bad is happening here.
(.. it's in non-strict environment. If she used use strict
, she would even have gotten an error. On the other hand, she gets no hint at all in her first seemingly working example - even when she has use strict; use warnings; use diagnostics
there.)
Now she wants to explore this weird behavior. Tries importing an empty list:
my @consts = ();
use Socket @consts;
printf "%d, %d\n", PF_INET, PF_INET6;
2, 10
surprisingly works as well, while it probably should not, like:
use Socket ();
printf "%d, %d\n", PF_INET, PF_INET6;
0, 0
Then she digs a little into those modules a little and realizes, that that the difference between the two modules is that these constants are / are not @EXPORT
ed, respectively.
Her conclusion is that the use Module @list
does not work as she is expecting.
What would be the best explanation for that? What is she doing wrong - What is the correct way of using pre-defined array in the use
statement?
Install the module properly using cpanm (or cpan or another CPAN installer). If you are using ActiveState Perl, then you probably should look to its PPM installer. on the command line. Actually, it can be any directory in the @INC list.
Try search.cpan.org/~bingos/Module-Load-0.32/lib/Module/Load.pm, or maybe even perldoc.perl.org/Module/Load.html.
The Comprehensive Perl Archive Network (CPAN) is a repository of over 250,000 software modules and accompanying documentation for 39,000 distributions, written in the Perl programming language by over 12,000 contributors.
This has to do with when the code is executed. use
is executed at compile time, while the my @list
is only executed at runtime. So the array does not exist a the point the module is loaded.
The module Socket exports PF_INET
and PF_INET6
by default, so it doesn't matter if you put it in the use
line. But Time::HiRes does not export stuff by default.
The error you get with strict
is:
Bareword "CLOCK_REALTIME" not allowed while "strict subs" in use ...
That tells us that Perl does not know that CLOCK_REALTIME
is a sub, which is true, because it was not loaded when we do this:
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
use Time::HiRes @consts;
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
What use
does is require
the module and import
the LIST of arguments at compile time. So it's the same as:
BEGIN {
require foo;
foo->import();
}
Knowing that, we can do it ourselves:
use strict; use warnings;
BEGIN {
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
require Time::HiRes;
Time::HiRes->import(@consts);
}
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
__END__
0, 1
Like this it will work, because the array @const
is defined in the same scope and is already available when the Perl interpreter executes it.
Because of scoping, just adding a BEGIN
block in front of the use will not work.
BEGIN {
my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
}
use Time::HiRes (@consts);
You can get around the problem by declaring the variable outside the BEGIN
block. That way it will be available in the next BEGIN
block's scope, and the value will already be set because the BEGIN
blocks are executed at compile time in FIFO order.
my @consts;
BEGIN {
@consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC);
}
use Time::HiRes (@consts);
printf "%d, %d\n", CLOCK_REALTIME, CLOCK_MONOTONIC;
__END__
0, 1
So to recap:
use strict
, you cannot easily find the problemBEGIN
block in front of the use
and place the my
declaration outside the BEGIN
, it worksrequire
instead of use
and import
yourself, you can also pass an arrayIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With