views:

169

answers:

3

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.

+12  A: 

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.

chaos
@chaos That's what i was afraid of :P Initially i wrote module A as i was told that it was going to be a standalone script, then it mutates into a web page LAMP style. thanks
melaos
+6  A: 

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.

jrockway
+2  A: 

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.)

ysth