7

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.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • 2
    Perl doesn't know it's a subroutine. You need to: `&getcwd` (not great), `use subs qw(getcwd);` (better), or simply `getcwd()` (best). – Matt Jacob Dec 12 '16 at 06:05
  • @MattJacob Thank you, that does work. However, the question remains, as explained in the note I added at the end. – zdim Dec 12 '16 at 07:18
  • The import hasn't yet worked as of when the getcwd call is compiled, so you get the strict error (or without strict, get it interpreted as the string `"getcwd"`). Adding the parentheses tells perl it is a sub call, not a bare word. – ysth Dec 12 '16 at 07:54
  • @ysth OK, thank you, I thought of that (_I can imagine that ..._) -- but it does work for other core modules, even with involved syntax. Say, in `List::Util` I can use `max BLOCK LIST`. One can say that this can go _because_ of the syntax (giving a hint to compiler or some such) ... but it shouldn't depend on that. How does one load dynamically then? I thought that this was the norm. – zdim Dec 12 '16 at 07:59
  • Depending on runtime import is not the norm, and not a good idea. – ysth Dec 12 '16 at 08:36
  • Indeed, but maybe it is necessary in this case. The point remain that having two different norms for parenthesis usage depending on an unknown rule is disturbing and should be clarified. – David Verdin Dec 12 '16 at 08:44
  • @ysth I meant that the "_norm_" is the code in the question. It's good to know if that isn't so, thank you. But how then? The code follows from the basic definition of `use` and I never saw a word against `import`-ing at runtime. It is also found in a number of well-regarded answers. How does one load at runtime then? – zdim Dec 12 '16 at 08:57
  • 1
    The point is you are Importing the module AFTER the compilation process. After changing eval { require Cwd; Cwd->import; }; into a Beginn-Block BEGIN { require Cwd; Cwd->import; }; everything works fine. – Georg Mavridis Dec 12 '16 at 14:48
  • You said you tried this for several different core modules, and some worked while others didn't. Can you show the exact code you used for each one? – ThisSuitIsBlackNot Dec 12 '16 at 16:35
  • @ThisSuitIsBlackNot I used the exact same code, just with names changed. For example, swap `'Cwd'` string for `'List::Util'`, add `'max'` to `import`, and write the test with `max`. (The tests happened to always need `func LIST` so doing `getcwd()` per Matt's comment never crossed my mind. But the question of failed imports remains.) – zdim Dec 12 '16 at 18:12
  • @GeorgMavridis The point of the question is to _load at runtime_. – zdim Dec 12 '16 at 18:13
  • @zdim That also fails. `perl -Mstrict -e'eval { require List::Util; List::Util->import("max") }; die "L::U" if $@; max 1..9'` Please show an example that works. – ThisSuitIsBlackNot Dec 12 '16 at 18:17
  • @ThisSuitIsBlackNot Added an example – zdim Dec 12 '16 at 18:23
  • @zdim That works because you're giving hints to the compiler in the form of parentheses. – ThisSuitIsBlackNot Dec 12 '16 at 18:26
  • @ThisSuitIsBlackNot Right, I got that after Matt's comment. Does that mean that one always has to use such syntax with modules loaded at runtime? Why is import failing? Why is this quasi-technique seen often in highly voted answers? How do I load non-core modules, for which hints don't help? As of now, I see _no way_ to load `List::MoreUtils` at runtime (for example). – zdim Dec 12 '16 at 18:29
  • 1) The import is not failing. 2) This has nothing to do with core vs. non-core. 3) The functions in List::MoreUtils use prototypes to emulate core functions like `grep`. Prototypes are ignored if the function declaration is not available at compile time, so you can't use the same syntax. – ThisSuitIsBlackNot Dec 12 '16 at 18:36

1 Answers1

6

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 );
ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
  • Thank you very much. So one _has to_ think of compiler and use different syntax when loading at runtime. That is good to know. (I've seen this around many times and never saw a hint of that.) – zdim Dec 14 '16 at 05:19
  • I thought of symbols not being known, as stated in the question, but then my perception that it "worked" for other modules made me believe that some magic was being done (for core modules, I thought). – zdim Dec 14 '16 at 05:20
  • You have to think about the parser even in other situations, e.g. `sub foo { ... } foo;` is okay but `foo; sub foo { ... }` isn't. So some people always use parentheses; it's just too easy to get bitten. And this is just one more example of why you should avoid prototypes. – ThisSuitIsBlackNot Dec 14 '16 at 15:39
  • Yes, that with prototypes is what threw me off for the whole thing. I never go near them (and don't know them) so I didn't realize that this module uses that. (Clearly, I need to reread Perl documentation far more carefully, and to make sure to always look at source for modules I use.) Thank you. – zdim Dec 15 '16 at 06:17