Reputation: 1139
I'm trying to switch some use
statements in my code to require
for modules I only use if certain conditions are met (e.g. the program might be loaded 1,000 times between times those modules are needed), in order to lower the overhead and improve the execution speed of my program (I've been using Devel::NYTProf to profile my code and some modules were adding significant execution time even when I didn't use them in a certain session).
I've run into an issue where the script dies on load because symbols aren't defined (that won't be defined until that module is imported). Is there a way to tell Perl that the symbols will be imported at runtime? A simple example: I only want to use Data::Dumper if I call a routine that triggers it:
sub dataDumper {
require Data::Dumper;
Data::Dumper->import;
say STDERR Dumper @_;
}
However, calling Dumper
on that third line causes an exception. I can work around that by referring to Data::Dumper->Dump
instead. However, a similar issue with LWP::UserAgent proves a bit sticker because LWP::UserAgent imports HTTP::Request. I haven't come up with a variation of my $request = new HTTP::Request GET => $params->{'url'};
that avoids throwing an exception.
Assuming I can that to work, is there any reason why this approach is a bad idea? Am I losing any sort of optimizations by not loading these modules at compile time? On a module like LWP, it seems like an easy call -- I just don't use it much. I'm a bit more confused on whether to try to dynamically switch between (for example) Text::Textile and Text::MultiMarkdown (I usually only need one per execution.
Upvotes: 2
Views: 428
Reputation: 132720
I do something similar, but like this. Somehow the state
makes this a lot faster even though require
won't load it a second time:
sub something {
state $rc = require Foo;
...
}
If I want to import things
sub something {
state $rc = do { require Foo; Foo->import };
...
}
Remember what use
actually is:
BEGIN {
require Foo;
Foo->import(...);
}
The BEGIN
merely does that at compile time. If you do all the same steps later, you end up in the same place (just later).
Upvotes: 2
Reputation: 385496
In sub calls, parens around arguments can only be omitted for declared subs.
say STDERR Dumper(@_);
Note that prototypes on subs you load this way will be ignored.
There is no problem with the second line as it doesn't involve a sub call. Method calls aren't affected.
$ perl -M5.010 -e'
if ($ARGV[0]) {
require LWP::UserAgent; # or HTTP::Request
my $request = new HTTP::Request GET => "https://stackoverflow.com";
}
say "ok";
' 0
ok
$ perl -M5.010 -e'
if ($ARGV[0]) {
require LWP::UserAgent; # or HTTP::Request
my $request = new HTTP::Request GET => "https://stackoverflow.com";
}
say "ok";
' 1
ok
As such, class modules are particularly useful here. Consider a plugin model in complicated cases.
Am I losing any sort of optimizations by not loading these modules at compile time?
Constants need to be replaced slower function calls which can't be folded.
$ perl -MO=Concise,-exec -M5.010 -e'
use constant FOO => 2;
say 2 + FOO;
'
...
2 <;> nextstate(main 188 -e:3) v:{,fea=1
3 <0> pushmark s
4 <$> const[IV 4] s/FOLD
5 <@> say vK
...
$ perl -MO=Concise,-exec -M5.010 -e'
say 2 + FOO();
require constant; import constant FOO => 2;
'
...
2 <;> nextstate(main 2 -e:2) v:{,fea=1
3 <0> pushmark s
4 <$> const[IV 2] s
5 <0> pushmark s
6 <#> gv[*FOO] s/EARLYCV
7 <1> entersub[t2] sKS/TARG
8 <2> add[t3] sK/2
9 <@> say vK
...
Upvotes: 5
Reputation: 54323
Use fully qualified names and don't import anything.
sub dataDumper {
require Data::Dumper;
say STDERR Data::Dumper::Dumper(@_);
}
However, a similar issue with LWP::UserAgent proves a bit sticker because LWP::UserAgent imports HTTP::Request.
The terminology in this statement is wrong. LWP::UserAgent doesn't import anything. In fact, it has no import
method at all. It loads HTTP::Request, by use
ing it. So perl will switch to compile time at the point LWP::UA is require
d, compile it, and load HTTP::Request, HTTP::Response and HTTP::Date (and a few others), all explicitly without importing anything into LWP::UserAgent's namespace either.
$request = new HTTP::Request GET => $params->{'url'};
I can't reproduce this blowing up if HTTP::Request hasn't been loaded. If it doesn't get executed, it won't error.
if (0) {
HTTP::Request->new(GET => '/foo');
new HTTP::Request GET => '/foo';
}
This is fine. You should of course use the first form, and not the indirect object notation, because it's ambiguous, but it makes no difference.
If you were to use HTTP::Request::Common, which imports GET
and POST
et al to quickly generate HTTP::Requests, you can also just require
it at runtime, and then use the fully qualified name.
if ($make_web_request) {
require LWP::UserAgent;
require HTTP::Request::Common;
my $ua = LWP::UserAgent->new;
$ua->request(HTTP::Request::Common::GET('https://example.org'));
}
Am I losing any sort of optimizations by not loading these modules at compile time?
No. If your code is started a lot of times, and goes lots of different paths, then loading things only if you need them is totally fine to do. It makes very little real difference. Perl switches between compile time and run time for every single require
anyway. Generally that's not a penalty at all.
Upvotes: 3