0

Coming from Python and Java background this is confusing me a bit. I have the following files:

Constants.pm

Utils.pl

Main.pl

Constants.pm has global variables that I'd like to share with Main.pl and Utils.pl.

Utils.pl has helper subs that I'd like to share with Constants.pm and Main.pl

#################### Constants.pm
package Constants;
require "Utils.pl";
use Exporter;
our @ISA = 'Exporter';

my %config = parseConfigFile("File.properties");

our @EXPORT = qw($var1 $var2 $var3);
our ($var1, $var2, $var3);

$var1 = $config{var1};
$var2 = $config{var2};
$var3 = $config{var3};


#################### Utils.pl
package Utils;
use Constants;

sub parseConfigFile {};
sub someSub {};

#################### Main.pl
use Constants;
require "Utils.pl"

my $var = someSub($var1);

When I run Main.pl I'm getting someSub is undefined error

Please help, thanks!

EDIT: I haven't tried @ikegami's answer instead I just moved everything in Constants into Utils.pm and importing Utils by using 'use' in main.pl

sql-noob
  • 383
  • 6
  • 16
  • 2
    `require "Utils.pl"` makes no sense. `Utils.pl` is not a module. – ikegami Jul 29 '15 at 17:54
  • 1
    Re "When I run Main.pl I'm getting someSub is undefined error", No, you get a syntax error. (`syntax error at a.pl line 4, near "my "`) – ikegami Jul 29 '15 at 17:55
  • second answer tells me I can use "require" http://stackoverflow.com/questions/1712016/how-do-i-include-functions-from-another-file-in-my-perl-script – sql-noob Jul 29 '15 at 17:57
  • 1
    `require` is for files with a `package`. `do` is for files without (which is a very bad practice). See [this](http://stackoverflow.com/a/6379109/589924) – ikegami Jul 29 '15 at 17:59
  • ok see the above update. I added "package Utils;" to Utils.pl but now I'm getting parseConfigFile is undefined at Constants.pm line 6 – sql-noob Jul 29 '15 at 18:09
  • You never import from from Utils, though – ikegami Jul 29 '15 at 18:10
  • (And why wouldn't you name the file `Utils.pm`?) – ikegami Jul 29 '15 at 18:11
  • What do you mean never import from Utils? I changed it Utils.pm but still getting the same error. – sql-noob Jul 29 '15 at 18:16
  • `use` is `require` + `import`. You bypassed the `import`, and you didn't setup `Utils` to export in the first place. – ikegami Jul 29 '15 at 18:25

1 Answers1

1

[The following explanation applies to the original version of the question. The solution is the same.]

require only executes a file once, but you expect the identical subs to be present in two packages. The simple solution is to use do instead of require. But then you end up with a poor design. You end up with multiple instances of the variables and subs created by Utils.pl. It's much better to convert Utils.pl into a proper module (like Constants.pm).

Constants.pm:

package Constants;

use strict;
use warnings;

use Exporter qw( import );
use Utils    qw( parseConfigFile );

our @EXPORT_OK = qw( $var1 $var2 $var3 );

my %config = parseConfigFile("File.properties");
our $var1 = $config{var1};
our $var2 = $config{var2};
our $var3 = $config{var3};

1;

Utils.pm:

package Utils;

use strict;
use warnings;

use Constants qw( ... );
use Exporter  qw( import );

our @EXPORT_OK = qw( parseConfigFile someSub );

sub parseConfigFile { ... }
sub someSub { ... }

1;

main.pl:

#!/usr/bin/perl

use strict;
use warnings;

use Constants qw( $var1 );
use Utils     qw( someSub );

my $var = someSub($var1);

But oops! Constants uses Utils, and Utils uses Constants, and they both import from the other. That's a problem. You can work around it, but there's no reason for parseConfigFile to be in Utils, so let's just avoid the problem entirely.

Constants.pm:

package Constants;

use strict;
use warnings;

use Exporter qw( import );

our @EXPORT_OK = qw( $var1 $var2 $var3 );

sub parseConfigFile { ... }

my %config = parseConfigFile("File.properties");
our $var1 = $config{var1};
our $var2 = $config{var2};
our $var3 = $config{var3};

1;

Utils.pm:

package Utils;

use strict;
use warnings;

use Constants qw( ... );
use Exporter  qw( import );

our @EXPORT_OK = qw( someSub );

sub someSub { ... }

1;

(I use @EXPORT_OK instead of @EXPORT because I believe it's a good idea to explicitly name your imports.)

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    How does `do` help? The subs would still get defined in the wrong package. – mob Jul 29 '15 at 18:34
  • 1
    @mob, Instead of being compiled into main *or* Constants, using `do` instead of `require` would have them compiled into both main *and* Constants. (Hum, the OP seems to have added `package Utils;`, completely negating my explanation.) – ikegami Jul 29 '15 at 20:26
  • @ikegami instead of separating into Constants and Utils and I just moved variables and subs into 'Utils.pm' and importing Utils by using 'use' in main.pl – sql-noob Jul 31 '15 at 13:38