Use different modules based on variable

G

geoffrobinson

Hi,

I have to do some error-checking on particular files. The routines I
will be calling will have the same name, but they need to be from
different modules based on a variable. (version 1.1, 2, etc.)

I assume that if I write "use Module1" within an if-block it will only
have scope within the if-block.

I'm trying to think of other options as well. "use only" doesn't quite
work because a single run of the script may want to call 1.1 and 2
during the same run, but at different times. In other words if file 1
needs a 1.1 error-checking routine, I want to use that, let it go out
of scope, and then use 2.2 if file 2 needs 2.2.

Please let me know if I am being unclear or confusing.

thanks for any help in advance,
Geoff
 
N

nilsonj

Hi,

I have to do some error-checking on particular files. The routines I
will be calling will have the same name, but they need to be from
different modules based on a variable. (version 1.1, 2, etc.)

I assume that if I write "use Module1" within an if-block it will only
have scope within the if-block.

I'm trying to think of other options as well. "use only" doesn't quite
work because a single run of the script may want to call 1.1 and 2
during the same run, but at different times. In other words if file 1
needs a 1.1 error-checking routine, I want to use that, let it go out
of scope, and then use 2.2 if file 2 needs 2.2.

Please let me know if I am being unclear or confusing.

thanks for any help in advance,
Geoff

Cleaner to instantiate them in separate classes and call them /
through/ a variable.

ie, Restructure your libs so that you have Checker::v2_2 and
Checker::v1_1 ... then instantiate an object of each ...

$thisChecker is Checker::v1_1;

Then call the member functions accordingly ...

$thisChecker->SomeCheckingFunction();
 
P

perlguru

Hi,

I have to do some error-checking on particular files. The routines I
will be calling will have the same name, but they need to be from
different modules based on a variable. (version 1.1, 2, etc.)

I assume that if I write "use Module1" within an if-block it will only
have scope within the if-block.

I'm trying to think of other options as well. "use only" doesn't quite
work because a single run of the script may want to call 1.1 and 2
during the same run, but at different times. In other words if file 1
needs a 1.1 error-checking routine, I want to use that, let it go out
of scope, and then use 2.2 if file 2 needs 2.2.

Please let me know if I am being unclear or confusing.

thanks for any help in advance,
Geoff

Make use of 'require' instead of 'use'. Remember that with 'use'
module is loaded at the compile timeitself, whereas with 'require' it
is loaded at the time when is requested. Below code may help you.

if ( $ver eq '1.1' ){
require "/usr/lib.../1.1/Module.pm";
Module::func();
}else{
require "/usr/lib.../2.2/Module.pm";
Module::func();
}
 
U

Uri Guttman

p> if ( $ver eq '1.1' ){
p> require "/usr/lib.../1.1/Module.pm";
p> Module::func();
p> }else{
p> require "/usr/lib.../2.2/Module.pm";
p> Module::func();
p> }

that won't work at all. read the actual need which is to call either one
during run time in the same run. require won't reload the module again
so only the last one loaded will ever be called. the OP has to name the
modules differently so they won't collide in the symbol table and both
can be loaded. then a basic dispatch table should do the trick for
calling one or the other.

uri
 
P

perlguru

p> if ( $ver eq '1.1' ){
p> require "/usr/lib.../1.1/Module.pm";
p> Module::func();
p> }else{
p> require "/usr/lib.../2.2/Module.pm";
p> Module::func();
p> }

that won't work at all. read the actual need which is to call either one
during run time in the same run. require won't reload the module again
so only the last one loaded will ever be called. the OP has to name the
modules differently so they won't collide in the symbol table and both
can be loaded. then a basic dispatch table should do the trick for
calling one or the other.

uri


have you given a try ? ... Give a hit !!, and see the result.
 
A

anno4000

geoffrobinson said:
Hi,

I have to do some error-checking on particular files. The routines I
will be calling will have the same name, but they need to be from
different modules based on a variable. (version 1.1, 2, etc.)

I assume that if I write "use Module1" within an if-block it will only
have scope within the if-block.

That assumption is wrong. While the effects of modules *can* be block
scoped, normally they aren't. In particular, the functions imported
by a module are package scoped and are valid outside the current block.

On the other hand, a "use" statement is executed at compile time,
independent of possible run-time conditionals.
I'm trying to think of other options as well. "use only" doesn't quite
work because a single run of the script may want to call 1.1 and 2
during the same run, but at different times. In other words if file 1
needs a 1.1 error-checking routine, I want to use that, let it go out
of scope, and then use 2.2 if file 2 needs 2.2.

So you need to switch back and forth between versions during the run
time of your script. Here is one way to do that:

Prepare two modules Module1.pm and Module2.pm that implement the
different versions of your function(s). Load both without importing
anything into your namespace. Then, in your main program, you can
define a function switch_version that imports the necessary functions
at run time. This is how it might look:

The main script:

use Module_1 ();
use Module_2 ();

sub switch_version {
my $version = shift;
my @functions = qw( gick);
for ( @functions ) {
no strict 'refs';
no warnings 'redefine';
*$_ = \ &{ join '::', "Module_$version", $_ };
}
}

switch_version 1;
gick();

switch_version 2;
gick();
__END__

Module1.pm:

package Module_1;
use warnings; use strict;

sub gick {
print "this is version 1\n"
}
1;

Module2.pm

package Module_2;
use warnings; use strict;

sub gick {
print "this is version 2\n"
}
1;

Anno
 
M

Mark Clements

geoffrobinson said:
Hi,

I have to do some error-checking on particular files. The routines I
will be calling will have the same name, but they need to be from
different modules based on a variable. (version 1.1, 2, etc.)

I assume that if I write "use Module1" within an if-block it will only
have scope within the if-block.

I'm trying to think of other options as well. "use only" doesn't quite
work because a single run of the script may want to call 1.1 and 2
during the same run, but at different times. In other words if file 1
needs a 1.1 error-checking routine, I want to use that, let it go out
of scope, and then use 2.2 if file 2 needs 2.2.

Please let me know if I am being unclear or confusing.

Uri has already suggested a dispatch table, but you could also try using
Factory and Strategy design patterns.

http://perldesignpatterns.com/?PerlDesignPatterns

should get you started, although its discussion of these particular
patterns is a bit limited.

Mark
 
T

Tad McClellan

perlguru said:
^^^^^^^^^^^^
p> if ( $ver eq '1.1' ){
p> require "/usr/lib.../1.1/Module.pm";
p> Module::func();
p> }else{
p> require "/usr/lib.../2.2/Module.pm";
p> Module::func();
p> }

that won't work at all. read the actual need which is to call either one
during run time in the same run.
^^^^^^^^^^^^


It is bad netiquette to quote .sigs.

have you given a try ?


Have you read what has already been said (twice!)?
 
U

Uri Guttman

Prepare two modules Module1.pm and Module2.pm that implement the
different versions of your function(s). Load both without importing
anything into your namespace. Then, in your main program, you can
define a function switch_version that imports the necessary functions
at run time. This is how it might look:

The main script:

use Module_1 ();
use Module_2 ();

sub switch_version {
my $version = shift;
my @functions = qw( gick);
for ( @functions ) {
no strict 'refs';
no warnings 'redefine';
*$_ = \ &{ join '::', "Module_$version", $_ };
}
}

that is way to complex IMO for this task. once you have separated the
namespaces, it is trivial to handle the different calls with a dispatch
table or similar polymorphism:

my %chooser = (

v1 => \&Module_1::gick,
v2 => \&Module_2::gick,
) ;

if you need more than 1 function then a multilevel hash is perfect:

my %chooser = (

v1 => {
foo => \&Module_1::foo,
bar => \&Module_1::bar,
},
v2 => {
foo => \&Module_2::foo,
bar => \&Module_2::bar,
},
) ;


my $vfunc = $chooser{$vers}{$func} or
die "bad version/func $vers/$func" ;
$vfunc->() ;

no strict issues, no symbol table hacking, etc.

uri
 
U

Uri Guttman

fc> BEGIN
fc> {
fc> eval "use x" if ...
fc> eval "use y" if ...
fc> }

that also fails as he wants to do this decision multiple times in a
run. and your code is already done with the 'if' pragma (but that
doesn't solve the OP's problem either).

uri
 
U

Uri Guttman

p> have you given a try ? ... Give a hit !!, and see the result.

have you tried it with multiple tries in a single process? if so, show
the code and results as i will be amazed if if works. require will not
reload a module as you think it does. and the modules will use the same
namespace so you can't have both loaded at one time.

uri
 
A

anno4000

Hey, what happened to your quote indicator? [fixed]
that is way to complex IMO for this task. once you have separated the
namespaces, it is trivial to handle the different calls with a dispatch
table or similar polymorphism:

my %chooser = (

v1 => \&Module_1::gick,
v2 => \&Module_2::gick,
) ;

if you need more than 1 function then a multilevel hash is perfect:

my %chooser = (

v1 => {
foo => \&Module_1::foo,
bar => \&Module_1::bar,
},
v2 => {
foo => \&Module_2::foo,
bar => \&Module_2::bar,
},
) ;


my $vfunc = $chooser{$vers}{$func} or
die "bad version/func $vers/$func" ;
$vfunc->() ;

no strict issues, no symbol table hacking, etc.

Well, the difference is really just whether you assign/reassign to
lexical coderefs (you) or package typeglobs (me). Whether you use an
intermediate hash is immaterial.

I was going for a solution that does exactly what the OP had in mind:
Make it behave (for a while) as if "use Module_1" had been run, and
switch (at runtime) to behave as if it had been "use Module_2". The
rest of the code can stay as it is. Your solution requires changes at
the call site. Cleanliness comes at a price :)

Okay... here is a variant that combines the merits of both solutions.
The interface is as the OP described it, so that function calls are
like calls of imported functions. You'll be happy to see your beloved
dispatch table re-emerge :)

use Module_1 ();
use Module_2 ();

{
my $version = 'v1';
sub switch_version { $version = shift }

my %gick = (
v1 => \ &Module_1::gick,
v2 => \ &Module_2::gick,
);

my %gack = (
# ...
);

sub gick {
goto $gick{ $version} || die "invalid version: $version";
}

sub gack {
# ...
}
}

gick;
switch_version( 'v2');
gick;

The use of "goto" makes sure that this works correctly even for
caller-sensitive functions. With just two versions, the symbol
table isn't really necessary.

goto $version eq 'v1' ? # etc

would have done.

Anno
 
G

geoffrobinson

I know this is delayed, but I finally got around to try this out.
Worked well.

A belated thanks to everyone who replied within this thread.
 

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
473,771
Messages
2,569,587
Members
45,099
Latest member
AmbrosePri
Top