Perl: use Module @list

Someone has the idea of ​​using an array variable instead of the array (list) literal in a use function expression, for example:

 my @list = qw(foo zoo); use Module @list; 

instead

 use Module qw(foo zoo); 

So she writes, for example:

 my @consts = qw(PF_INET PF_INET6); use Socket @consts; printf "%d, %d\n", PF_INET, PF_INET6; 

which seems to work as expected:

2, 10

Then she does this with another module, for example. Time::HiRes . Instead

 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, as if it was working with the Socket module! There is something bad here.

(.. he is in a non-strict environment. If she used use strict , she would even be mistaken. On the other hand, she has no hint of everything in her first seemingly working example - even when she use strict; use warnings; use diagnostics there.)

Now she wants to learn this strange behavior. Requests the import of an empty list:

 my @consts = (); use Socket @consts; printf "%d, %d\n", PF_INET, PF_INET6; 

2, 10

surprisingly works, but probably it is not, for example:

 use Socket (); printf "%d, %d\n", PF_INET, PF_INET6; 

0, 0

Then she delves a bit into these modules and realizes that the difference between the two modules is that these constants / are not @EXPORT ed respectively.

Her conclusion is that use Module @list does not work as it expects.

What would be the best explanation? What is she doing wrong? What is the correct way to use a predefined array in a use statement?

+7
perl use
source share
1 answer

This is due to when the code is executed. use is executed at compile time, and my @list is executed only at run time. Thus, the array is not the point at which the module is loaded.

The Socket Export module is PF_INET and PF_INET6 by default, so it doesn't matter if you put it in use . But Time :: HiRes does not export material by default .

Error with strict :

The bas-relief "CLOCK_REALTIME" is not allowed while using "strict subnets" ...

This 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 the require module and import LIST of arguments at compile time. So this is 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 

It will work similarly, since the @const array @const defined in the same scope and is already available when the Perl interpreter executes it.

Due to visibility, simply adding a BEGIN block before use will not work.

 BEGIN { my @consts = qw(CLOCK_REALTIME CLOCK_MONOTONIC); } use Time::HiRes (@consts); 

You can work around the problem by declaring a variable outside the BEGIN block. This way it will be available in the next BEGIN , and the value will already be set, since BEGIN blocks are executed at compile time in the 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 repeat:

  • because of two things: scope and execution order
  • the fact that you are passing an array is not a problem here - the array will be the part of the LIST that is being passed
  • If you do not use strict , you cannot easily find the problem
  • if you add a BEGIN block before use and place my declaration outside BEGIN , it works
  • If you take require instead of use and import yourself, you can also pass an array
+19
source share

All Articles