Perl: use Module @list
perl, perl-module
Solution
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:
- it's because of two things: scope and order of execution
- the fact that you pass an array is not the issue here - the array will be part of the LIST that is passed
- if you do not `use strict`, you cannot easily find the problem
- if you add a `BEGIN` block in front of the `use` and place the `my` declaration outside the `BEGIN`, it works
- if you take `require` instead of `use` and `import` yourself, you can also pass an array
Problem
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?