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 @EXPORTed, 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?
This has to do with when the code is executed.
useis executed at compile time, while themy @listis only executed at runtime. So the array does not exist a the point the module is loaded.The module Socket exports
PF_INETandPF_INET6by default, so it doesn't matter if you put it in theuseline. But Time::HiRes does not export stuff by default.The error you get with
strictis:That tells us that Perl does not know that
CLOCK_REALTIMEis a sub, which is true, because it was not loaded when we do this:What
usedoes isrequirethe module andimportthe LIST of arguments at compile time. So it's the same as:Knowing that, we can do it ourselves:
Like this it will work, because the array
@constis defined in the same scope and is already available when the Perl interpreter executes it.Because of scoping, just adding a
BEGINblock in front of the use will not work.You can get around the problem by declaring the variable outside the
BEGINblock. That way it will be available in the nextBEGINblock's scope, and the value will already be set because theBEGINblocks are executed at compile time in FIFO order.So to recap:
use strict, you cannot easily find the problemBEGINblock in front of theuseand place themydeclaration outside theBEGIN, it worksrequireinstead ofuseandimportyourself, you can also pass an array