checking at runtime if modul is installed

S

Sam

Hello,

is there a way to check if a modul is available and if so then to use it
I want to do

use Time:HiRes qw (time);

if possible; but it should also run if that is not available.

Thanks,
Sam
 
S

Sherm Pendley

Sam said:
is there a way to check if a modul is available and if so then to use it
I want to do

use Time:HiRes qw (time);

if possible; but it should also run if that is not available.

Wrap it up in an eval() and check for errors. Be sure to put the eval()
in a BEGIN block so it happens at compile time, like use() normally does.

BEGIN {
unless (eval "use Time::HiRes qw(time)") {
warn "Couldn't load Time::HiRes: $@";
}
}

sherm--
 
A

Anno Siegel

Sherm Pendley said:
Wrap it up in an eval() and check for errors. Be sure to put the eval()
in a BEGIN block so it happens at compile time, like use() normally does.

BEGIN {
unless (eval "use Time::HiRes qw(time)") {
warn "Couldn't load Time::HiRes: $@";
}
}

That isn't quite right. "use" returns nothing at run time, whether it
succeeded or not. You need to check $@. Also, I would use block eval
when string eval isn't necessary. So

BEGIN {
eval { use Time::HiRes qw(time) };
warn "Couldn't load module: $@" if $@;
}

Anno
 
S

Sherm Pendley

Anno said:
That isn't quite right. "use" returns nothing at run time, whether it
succeeded or not.

Use() doesn't return anything, but it *does* die if the module can't be
found, and the eval() returns false if that happens. So you can put the
eval() in a conditional block, or check $@ afterwards - it works either way.
Also, I would use block eval when string eval isn't necessary. So

BEGIN {
eval { use Time::HiRes qw(time) };
warn "Couldn't load module: $@" if $@;
}

A string eval *is* necessary here because of the different semantics of
a block vs. a string eval. A string eval turns compile-time errors that
happen within the evaled string into run-time errors. A block eval won't
do that; compile-time errors within the block cause the script as a
whole to die.

Examine the output of this:

BEGIN {
unless (eval 'use NoSuchModule' ) {
warn "My custom error: $@";
}
}

This prints "My custom error: Can't locate NoSuchModule.pm in @INC (@INC
contains: ...) at (eval 1) line 2.", but it's a warning not an error,
and the program continues.

Compare that to the output from this:

BEGIN {
unless (eval {use NoSuchModule}) {
warn "My custom error: $@";
}
}

This prints "Can't locate NoSuchModule.pm in @INC (@INC contains: ...)
at ./test.pl line 7.". Note the location of the error, and the lack of
the error printed by warn() - the script as a whole failed to compile,
and eval() didn't catch the error.

sherm--
 
T

Tassilo v. Parseval

Also sprach Sherm Pendley:
Anno Siegel wrote:

A string eval *is* necessary here because of the different semantics of
a block vs. a string eval. A string eval turns compile-time errors that
happen within the evaled string into run-time errors. A block eval won't
do that; compile-time errors within the block cause the script as a
whole to die.

This is true. However, this whole issue can be avoided by using
'require'. One standard idiom would be:

use constant HAVE_MODULE => eval { require Module; 1 } || 0;

BEGIN {
warn "Could't load Module: $@" if ! HAVE_MODULE;
}

'use' happens to be the wrong tool for that.

Tassilo
 
S

Sherm Pendley

Tassilo said:
This is true. However, this whole issue can be avoided by using
'require'. One standard idiom would be:

use constant HAVE_MODULE => eval { require Module; 1 } || 0;

If you do it this way, don't forget to call import() manually -
require() won't do that for you like use() would:

use constant HAVE_MODULE => eval {
require Module;
Module::import LIST;
1;
}

That works, but it's rather wordy, in my opinion, and trouble-prone if
you forget to call import() - as you did in your example. I'd rather
stay with use().

sherm--
 
B

Brian McCauley

Sherm said:
Use() doesn't return anything, but it *does* die if the module can't be
found, and the eval() returns false if that happens.

Yes but that is not the only situation in which eval will return false.
So you can put the
eval() in a conditional block, or check $@ afterwards - it works either
way.

It may happen to work but the behaviour is undefined so it may happen
not to work in future.

If you want to use the truth of the return from eval(STRING) as an
indicator of success it is best to explicitly ensure that it will be
true on success.

BEGIN {
unless (eval "use Time::HiRes qw(time); 1") {
warn "Couldn't load Time::HiRes: $@";
}
}
 
A

Anno Siegel

Sherm Pendley said:
Use() doesn't return anything, but it *does* die if the module can't be
found, and the eval() returns false if that happens. So you can put the
eval() in a conditional block, or check $@ afterwards - it works either way.

It also returns false when it *can* load the module. Watch

my $succ;
BEGIN { $succ = eval "use Time::HiRes" }
print Time::HiRes::time, "\n"; # show it's loaded
print "undefined\n" unless defined $succ;

.... which prints

1105138968.24501
undefined
A string eval *is* necessary here because of the different semantics of

Yes, I noticed. I had been playing with "require" and didn't make
the switch, sorry.

Anno
 
T

Tassilo v. Parseval

Also sprach Sherm Pendley:
If you do it this way, don't forget to call import() manually -
require() won't do that for you like use() would:

use constant HAVE_MODULE => eval {
require Module;
Module::import LIST;
Rather:

Module->import(LIST);

1;
}

That works, but it's rather wordy, in my opinion, and trouble-prone if
you forget to call import() - as you did in your example. I'd rather
stay with use().

I didn't follow this thread too closely and based my posting mostly on
the subject line. If you additionally want to import symbols from the
module to be checked, I'd still go with 'require' even if it costs one
additional statement. I find the idea of forcing a compiletime
expression into runtime by using STRING-eval a little kludgy. This is
mostly a stylistic question for me. Technically there is nothing
objectionable about a STRING-eval here.

Tassilo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,440
Latest member
YoungBorel

Latest Threads

Top