Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot load `Cwd` (and other, non-core, modules) at runtime

Imagine I want to load a module at runtime. I expected this to work

use warnings;
use strict;

eval {
    require Cwd; 
    Cwd->import;
};
if ($@) { die "Can't load Cwd: $@" }

say "Dir: ", getcwd;

but it doesn't, per Bareword "getcwd" not allowed ....

The Cwd exports getcwd by default. I tried giving the function name(s) to import and I tried with its other functions. It works with the full name, say Cwd::getcwd, so I'd think that it isn't importing.

This works as attempted for a few other core modules that I tried, for example

use warnings;
use strict;

eval { 
    require List::Util; 
    List::Util->import('max');
};
if ($@) { die "Can't load List::Util: $@" }

my $max = max (1, 14, 3, 26, 2); 
print "Max is $max\n";

NOTE added   Apparently, function calls with parenthesis give a clue to the compiler. However, in my opinion the question remains, please see EDIT at the end. In addition, a function like first BLOCK LIST from the module above does not work.


However, it does not work for a few (well established) non-core modules that I tried. Worse and more confusingly, it does not work even with the fully qualified names.

I can imagine that the symbol (function) used is not known at compile time if require is used at runtime, but it works for (other) core modules. I thought that this was a standard way to load at runtime.

If I need to use full names when loading dynamically then fine, but what is it with the inconsistency? And how do I load (and use) non-core modules at runtime?

I also tried with Module::Load::Conditional and it did not work.

What am I missing, and how does one load modules at runtime?   (Tried with 5.16 and 5.10.1.)


EDIT

As noted by Matt Jacob, a call with parenthesis works, getcwd(). However, given perlsub

NAME LIST; # Parentheses optional if predeclared/imported.

this implies that the import didn't work and the question of why remains.

Besides, having to use varied syntax based on how the module is loaded is not good. Also, I cannot get non-core modules to work this way, specially the ones with syntax like List::MoreUtils has.

like image 694
zdim Avatar asked Dec 12 '16 05:12

zdim


1 Answers

First, this has nothing to do with core vs. non-core modules. It happens when the parser has to guess whether a particular token is a function call.


eval {
    require Cwd; 
    Cwd->import;
};
if ($@) { die "Can't load Cwd: $@" }

say "Dir: ", getcwd;

At compile time, there is no getcwd in the main:: symbol table. Without any hints to indicate that it's a function (getcwd() or &getcwd), the parser has no way to know, and strict complains.


eval { 
    require List::Util; 
    List::Util->import('max');
};
if ($@) { die "Can't load List::Util: $@" }

my $max = max (1, 14, 3, 26, 2);

At compile time, there is no max in the main:: symbol table. However, since you call max with parentheses, the parser can guess that it's a function that will be defined later, so strict doesn't complain.

In both cases, the strict check happens before import is ever called.


List::MoreUtils is special because the functions use prototypes. Prototypes are ignored if the function definition is not visible at compile time. So, not only do you have to give the parser a hint that you're calling a function, you also have to call it differently since the prototype will be ignored:

use strict;
use warnings 'all';
use 5.010;

eval {
    require List::MoreUtils;
    List::MoreUtils->import('any')
};
die "Can't load List::MoreUtils: $@" if $@;

say 'found' if any( sub { $_ > 5 }, 1..9 );
like image 65
ThisSuitIsBlackNot Avatar answered Oct 08 '22 13:10

ThisSuitIsBlackNot