Re: Redefined subroutines in multiple libraries
by tilly (Archbishop) on Jan 10, 2009 at 00:12 UTC
|
Having a circular dependency like this is generally a sign of tight coupling, which is a bad thing. Other people have suggested that you create modules. That is just a way to repackage the problem so it shows up in a different way. See my reply to ikegami for an explanation of how it shows up if you do that.
The safe solution is to move one require inside of a function call. So, for instance, move the require of libB.pl into subroutine A. This is only going to actually load the other library once, so don't worry about performance. For an example of this in the Perl core, Carp needs to use Exporter to export functions, and Exporter uses Carp to report problems. In that case Carp is loaded on demand from within Exporter.
This solves the real problem, but does nothing about your fairly harmless warning. To remove your warning you merely need to write a script that requires one of the libraries rather than run the libraries as programs in their own right.
(Random tip. Renaming libA.pl to libA.pm and putting a package statement in it is a very easy change to make, and brings all sorts of side benefits. You can use Exporter to export functions, and as a bonus it will be easier when debugging to figure out which functions came from where.) | [reply] |
Re: Redefined subroutines in multiple libraries
by kennethk (Abbot) on Jan 09, 2009 at 21:06 UTC
|
I think this is usually resolved by abstracting the subroutines into modules. Is there a specific reason for not packing the subroutines into one or more library modules and calling them from the smaller script files? A work-around hack, which is really dodging the issue, would be to declare no warnings "redefine"; before the relevant script entries.
Unless I'm mistaken, won't this circular require result in, when called from libA.pl, libA.pl being run twice and libB.pl being run once? This implies to me that the scripts contain only a list of subroutines, further suggesting that modules are a good idea.
| [reply] [d/l] |
Re: Redefined subroutines in multiple libraries
by targetsmart (Curate) on Jan 10, 2009 at 03:19 UTC
|
I believe that other monks have helped you, but still if you will face the problem of using libA.pm routines in libB.pm and viceversa, (you have to read perlmod, perlmodlib, and 'intermediate perl' book for some reference) for that you need to properly define the reusable routines in the appropriate modules,
when it comes to calling routines, you can have another module Objects.pm which maintains the objects of the other two modules(liba and libb) and this objects.pm will be used to share the objects variable to across libA and libB, so that the calling becomes easy.
Some hints for Objects.pm and example code is below
# register object in objects.pm
sub RegisterObject
{
my ($Pack,$Object,$Tag) = @_;
my ($Name);
$Name = uc($Tag) . 'OBJ';
$Pack->{'Objects'}->{$Name}->[0] = $Object;
$Pack->{'Objects'}->{$Name}->[1] = $Tag;
print STDERR "Registered Object $Tag with Objects Handler\n";
}
# autoload in object.pm
sub AUTOLOAD
{
my ($Pack) = shift;
my ($Type,$Calledas,$Key,$Name);
if (ref($Pack)) { $Type = ref($Pack); }
else
{
print STDERR "$Pack is not an Object\n";
exit(1);
}
$Calledas = $AUTOLOAD;
$Calledas =~ s/.*://;
foreach $Key (keys(%{$Pack->{'Objects'}}))
{
if ($Pack->{'Objects'}->{$Key}->[1] eq $Calledas)
{
return($Pack->{'Objects'}->{$Key}->[0]);
}
}
print STDERR "%%%%%%% Unregistered Object - AUTOLOAD Called as $Ca
+lledas %%%%%%%%\n";
return(-1);
}
# from your main script register the objects of liba and libb.
# the $main::Objects must be the object of Objects.pm.
$main::Objects->RegisterObject($BlessedObjectRef, $ObjectName);
# you have to pass $main::Objects to liba and libb during object creat
+ion(probable in new())
# from there on your liba can use libb routines like
$main::Objects->liba->routineX()
# which will call autoload and retrieve the object of liba and call th
+e routineX.
# the same can be used in libb.
I believe that I haven't confused you, the above is just an example, I hope it will help you
I have been using the above Objects.pm technique for years.
It is helping me to manage multiple module's objects and calling routines among themselves. | [reply] [d/l] |
Re: Redefined subroutines in multiple libraries
by scorpio17 (Canon) on Jan 09, 2009 at 21:42 UTC
|
If you don't want to make your libraries into modules (which tends to imply object oriented methodology, etc.)
you might instead put them into packages. If your familiar
with C++, this is the same idea as putting them into a
unique namespace.
Here's a real simple example:
This is file MySub1.pm:
package MySub1;
use MySub2;
sub AAA {
my $x = MySub2::DDD();
return "AAA : $x";
}
sub BBB {
return "BBB";
}
1;
This is file MySub2.pm:
package MySub2;
use MySub1;
sub CCC {
my $x = MySub1::BBB();
return "CCC : $x";
}
sub DDD {
return "DDD";
}
1;
This is file mytest.pl:
use strict;
use MySub1;
use MySub2;
print MySub1::AAA(), "\n";
print MySub1::BBB(), "\n";
print MySub2::CCC(), "\n";
print MySub2::DDD(), "\n";
Summary: so you have MySub1, a package that contains subroutines, some of which call other subroutines in MySub2; and MySub2 contains subroutines that call subroutines in MySub1. The actual perl script uses subroutines from each of these packages.
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
scorpio17: The example you provided illustrates the problem, but doesn't solve it. Try adding "use strict; use warnings;" to each and run MySub1.pm:
> MySub1.pm
Subroutine AAA redefined at MySub1.pm line 9.
Subroutine BBB redefined at MySub1.pm line 14.
As far as I can tell, putting the files into packages has no effect, at least not with respect to this problem. If I remove the package statements from each file, the same warning occurs.
Jim | [reply] [d/l] |
|
|
Don't execute modules as scripts.
perl -e"use MySub1"
will be clean. | [reply] [d/l] |
|
|
Re: Redefined subroutines in multiple libraries
by bart (Canon) on Jan 10, 2009 at 12:21 UTC
|
I can avoid this by putting all the subroutines in the same file, but that is undesirable.
Yet, it's the only solution that makes sense.
The two subroutines are thus tightly coupled, that it makes no sense to separate them.
Perhaps you can separate them from the rest of the subroutines in those library files, put the 2 subroutines together in their own file.
| [reply] |
Re: Redefined subroutines in multiple libraries
by shawnhcorey (Friar) on Jan 10, 2009 at 16:12 UTC
|
If you have two sub's with the same name in the same package, the last one compiled will be the one in effect. To fix your problem, place the sub's in difference packages. | [reply] |
Re: Redefined subroutines in multiple libraries
by locked_user sundialsvc4 (Abbot) on Jan 11, 2009 at 01:57 UTC
|
If you use packages, you create two distinct namespaces, which resolves the ambiguity. pkg1:mysub and pkg2::mysub are recognized to be separate and unrelated.
| |