Reputation: 8418
Unfortunately, I'm a totally noob when it comes to creating packages, exporting, etc in Perl. I tried reading some of the modules and often found myself dozing off from the long chapters. It would be helpful if I can find what I need to understand in just one simple webpage without the need to scroll down. :P
Basically I have two modules, A & B, and A will use some function off from B and B will use some functions off from A. I get a tons of warning about function redefined when I try to compile via perl -c
.
Is there a way to do this properly? Or is my design retarded? If so what would be a better way? As the reason I did this is to avoid copy n pasting the other module functions again into this module and renaming them.
Upvotes: 1
Views: 270
Reputation: 98398
The simple answer is to not test compile modules with perl -c... use perl -e'use Module' or perl -e0 -MModule instead. perl -c is designed for doing a test compile of a script, not a module. When you run it on one of your
When recursively using modules, the key point is to make sure anything externally referenced is set up early. Usually this means at least making use @ISA be set in a compile time construct (in BEGIN{} or via "use parent" or the deprecated "use base") and @EXPORT and friends be set in BEGIN{}.
The basic problem is that if module Foo uses module Bar (which uses Foo), compilation of Foo stops right at that point until Bar is fully compiled and it's mainline code has executed. Making sure that whatever parts of Foo Bar's compile and run-of-mainline-code need are there is the answer.
(In many cases, you can sensibly separate out the functionality into more modules and break the recursion. This is best of all.)
Upvotes: 2
Reputation: 42674
So... the suggestion to factor out common code into another module is
a good one. But, you shouldn't name modules *.pl, and you shouldn't
load them by require
-ing a certain pathname (as in require
"../lib/foo.pl";
). (For one thing, saying '..' makes your script
depend on being executed from the same working directory every time.
So your script may work when you run it as perl foo.pl
, but it won't
work when you run it as perl YourApp/foo.pl
. That is generally not good.)
Let's say your app is called YourApp. You should build your
application as a set of modules that live in a lib/
directory. For
example, here is a "Foo" module; its filename is lib/YourApp/Foo.pm
.
package YourApp::Foo;
use strict;
sub do_something {
# code goes here
}
Now, let's say you have a module called "Bar" that depends on "Foo".
You just make lib/YourApp/Bar.pm
and say:
package YourApp::Bar;
use strict;
use YourApp::Foo;
sub do_something_else {
return YourApp::Foo::do_something() + 1;
}
(As an advanced exercise, you can use Sub::Exporter
or Exporter
to
make use YourApp::Foo
install subroutines in the consuming package's
namespace, so that you don't have to write YourApp::Foo::
before
everything.)
Anyway, you build your whole app like this. Logical pieces of functionally should be grouped together in modules (or even better, classes).
To make all this run, you write a small script that looks like this (I
put these in bin/
, so let's call it bin/yourapp.pl
):
#!/usr/bin/env perl
use strict;
use warnings;
use feature ':5.10';
use FindBin qw($Bin);
use lib "$Bin/../lib";
use YourApp;
YourApp::run(@ARGV);
The key here is that none of your code is outside of modules, except a tiny bit of boilerplate to start your app running. This is easy to maintain, and more importantly, it makes it easy to write automated tests. Instead of running something from the command-line, you can just call a function with some values.
Anyway, this is probably off-topic now. But I think it's important to know.
Upvotes: 6
Reputation: 124297
It's not really good practice to have circular dependencies. I'd advise factoring something or another to a third module so you can have A depends on B, A depends on C, B depends on C.
Upvotes: 12