geckosan has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

I have two modules, interface1.pm and interface2.pm. They contain different sets of functions with the same names. Is there any way I can use both of them, and call the function I want by name, the module it uses being dependant on a variable?

For example, if I call the function terraform which is described in both interfaces and the variable $version is 1, then the interface1.pm version of terraform will be used. If version was 2, interface2.pm would be used.

That's what I'd like. Of course I'm noticing I can't load the two sets of functions without them overwriting each other, even if I say:

use interface1 (); use interface2 ();
I was hoping I could do that, and then use a combination of use and no when I wanted to switch "versions" in the program. But no, foiled at the outset.

I might be approaching this improperly, if so please nudge me in the right direction.

Thanks a lot!

GrandFather altered the title. Title was versioning

Replies are listed 'Best First'.
Re: Calling same named functions from different modules
by Tanktalus (Canon) on Oct 25, 2005 at 04:17 UTC

    Sure. There are a few ways. The most obvious to me, being somewhat of an OO guy, is to modify the functions to become methods - even just package methods. This is as simple as throwing away the first parameter. Then you can do something like this:

    my %versions = ( 1 => 'interface1', 2 => 'interface2' ); my $interface = $versions{$version}; $interface->some_func();

    If you can't go and modify the interfaces, perhaps you can play with the imports a bit. This is a bit more dangerous, but probably will work.

    my %versions = ( 1 => 'interface1', 2 => 'interface2' ); my $interface = $versions{$version}; $interface->import(); some_func();

    Just realise that the currently-imported version is a global variable (*some_func), with all the repurcussions that implies. You may also get method-redefined messages, although I don't think so, so please test it ;-)

Re: Calling same named functions from different modules
by holli (Abbot) on Oct 25, 2005 at 07:05 UTC
    First of all, all lowercase module names are reserved for perl pragmas. You better name your modules "Interface1" and "Interface2" respectively.
    For example, if I call the function terraform which is described in both interfaces and the variable $version is 1, then the interface1.pm version of terraform will be used. If version was 2, interface2.pm would be used.
    If I get you right you want something like this:
    #file Interface1.pm package Interface1; sub foo { return "I am one!\n"; } 1; #file Interface2.pm package Interface2; sub foo { return "I am two!\n"; } 1; #file script.pl use strict; use warnings; use Interface1; use Interface2; my $interface; $interface = "Interface1"; print $interface->foo(); $interface = "Interface2"; print $interface->foo();
    Edit:
    or without "class method syntax":
    $interface = "Interface1"; eval "print $interface" . "::foo()"; $interface = "Interface2"; eval "print $interface" . "::foo()";
    Note that you have to use the concatenation here, because perl would interpret
    eval "print $interface::foo()";
    as a reference to the variable $foo in package Interface1 and that fails.


    holli, /regexed monk/
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Calling same named functions from different modules
by Zaxo (Archbishop) on Oct 25, 2005 at 05:02 UTC

    If you don't want to use namespaces, but to have whichever version you load provide functions in the current namespace, you can use if . . . to get conditional loading of the libraries. Just be sure that $version is set at compile time so use knows about it.

    my $version; BEGIN { $version = shift || whatever(); } use if 1 == $version, 'interface1'; use if 2 == $version, 'interface2';
    You can play with the logic to get a default version so long as you make sure the decisions are mutually exclusive. Even that isn't carved in stone: you can make warnings.pm ignore sub redefinitions with the lexical no warnings 'redefine';.

    After Compline,
    Zaxo

Re: Calling same named functions from different modules
by sauoq (Abbot) on Oct 25, 2005 at 12:48 UTC
    I'm noticing I can't load the two sets of functions without them overwriting each other
    . . .
    I was hoping I could do that, and then use a combination of use and no when I wanted to switch "versions" in the program.

    As you've noticed from the other responses, there are several ways to get something close to what you want. From the quotes above and your wording in general (talking about "versioning" for instance) it seems that maybe you have existing code that you want to change as little as possible but you want to pull in the new "version" of some functions as needed? Are you debugging or trying to test a new module piecemeal?

    If that's the case, you might want to manually import the subs you want when you want them. Some aliasing as simple as:

    { no warnings 'redefine'; *foo = \&Interface1::foo; } print foo(); { no warnings 'redefine'; *foo = \&Interface2::foo; } print foo();
    might do what you need. If you need a bit more flexibility, you could wrap that up in a sub like:
    sub use_from { no strict 'refs'; no warnings 'redefine'; my $package = shift; *{ $_ } = *{ "$package\::$_" }{CODE} for @_; }
    Which you could then use like:
    use_from('Interface1', 'foo', 'bar'); foo(); bar() use_from('Interface2', 'foo', 'bar') foo(); bar();

    For the sake of maintainability, you probably wouldn't want to leave this stuff in production code. But it can be handy during development.

    -sauoq
    "My two cents aren't worth a dime.";