23

I want to do something like this in Perl:

$Module1="ReportHashFile1"; # ReportHashFile1.pm
$Module2="ReportHashFile2"; # ReportHashFile2.pm

if(Condition1)
{
  use $Module1;
}
elsif(Condition2)
{
  use $Module2;
}

ReportHashFile*.pm contains a package ReportHashFile* .

Also how to reference an array inside module based on dynamic module name?

@Array= @$Module1::Array_inside_module;

Is there anyway I can achieve this. Some sort of compiler directive?

4 Answers 4

28

You might find the if module useful for this.

Otherwise the basic idea is to use require, which happens at run-time, instead of use, which happens at compile-time. Note that '

BEGIN {
    my $module = $condition ? $Module1 : $Module2;
    my $file = $module;
    $file =~ s[::][/]g;
    $file .= '.pm';
    require $file;
    $module->import;
}

As for addressing globals, it might be easier if you just exported the variable or a function returning it to the caller, which you could use by its unqualified name. Otherwise there's also the possibility of using a method and calling it as $Module->method_name.

Alternatively, you could use symbolic references as documented in perlref. However, that's usually quite a code smell.

my @array = do {
    no strict 'refs';
    @{ ${ "${Module}::Array_inside_module" } };
};
Sign up to request clarification or add additional context in comments.

2 Comments

+1 for addressing "How do I call a method with the same name from whichever module I loaded" :)
I usually throw an eval in there in case you can't load the module. I like to shut things down nicely instead of seeing that awful dump of @INC that perl spits out. :)
13

Unless the execution speed is important, you can use string eval:

if (Condition1) {
    eval "use $Module1"; die $@ if $@;
}
elsif (Condition2) {
    eval "use $Module2"; die $@ if $@;
}

Comments

6

People have already told you how you can load the module with Perl primitives. There's also Module::Load::Conditional.

If you're looking to access an array of the same name no matter which module you loaded, consider making a method for that so you can skip the symbolic reference stuff. Give each module a method of the same name:

package ReportHashFileFoo;
our @some_package_variable;
sub get_array { \@some_package_variable }

Then, when you load that module:

if( ... some condition ... ) {
    eval "use $module" or croak ...;
    my $array_ref = $module->get_array;
    }

2023 update Lately I've been using require in a state expression since that only happens once in the scope:

use v5.10;

if( ... some condition ... ) {
    state $rc =  require $module;
    my $array_ref = $module->get_array;
    }

I don't know what you're really doing (XY Problem), but there's probably a better design. When things seem tricky like this, it's usually because you're overlooking a better way to to it.

Comments

5

Maybe helpful...

A little example for debugging.

sub DEBUG () {1};               # It's the condition (may be a debuglevel...)

use if DEBUG, Data::Dumper;     # Conditionally load

my $testvar = "foo";
print "Testing: $testvar\n" if     DEBUG;
print "No testing\n"        unless DEBUG;

print Dumper \$testvar if DEBUG;  # "Dumper" only available if "DEBUG" returns "true".

Output with sub DEBUG () {1};

Testing: foo
$VAR1 = \'foo';

Output with sub DEBUG () {0};

No testing

q.v. perldoc.perl.org/if

1 Comment

I think the module needs to be a string? e.g. use if DEBUG, "Data::Dumper";

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.