ThePracticalOne
ThePracticalOne

Reputation: 651

Make required script use variables from another required script

I have two modules: test1 and test2 and I need to run their subroutines in sequence. They need to modify the same variable $var and the outer script needs to print the final result. This unfortunately doesn't work, and seems to be very similar to this S.O. Question.

#test1.pm
use strict;
package test1;
my $var;
sub step1 {
  $var = "Hello";
}
1;

#test2.pm
use strict;
package test2;
my $var;
sub step1 {
    $var = $var." World!\n";
}
1;

#execTests.pl
use strict;
require test1;
require test2;
&test1::step1;
&test2::step1;
print $test2::var;

How do I make $var be included in the same scope of both required packages?

Upvotes: 2

Views: 130

Answers (3)

Borodin
Borodin

Reputation: 126722

The main issue is that a variable declared with my isn't a package variable and cannot be accessed by fully-qualifying it with the package name. However even if you declare package variables instead by using our, you still have test1.pm and execTests,pl referring to $test1::var while test2.pm is working with $test2::var

I suggest you use a variable local to you main program instead, and pass it to the two steps for modification

Something like this (tested and working)

test1.pm

use strict;
use warnings;

package test1;

use parent 'Exporter';
our @EXPORT = qw/step1/;

sub step1 {
  $_[0] = "Hello";
}

1;

test2.pm

use strict;
use warnings;

package test2;

use parent 'Exporter';
our @EXPORT = qw/step2/;

sub step2 {
    $_[0] .= " World!\n";
}

1;

execTests.pl

use strict;
use warnings;

use test1;
use test2;

my $var;

step1($var);
step2($var);

print $var;

output

Hello World!

Upvotes: 1

Mark Nunberg
Mark Nunberg

Reputation: 3691

With the obvious disclaimer that this is BAD BAD BAD DESIGN you can simply utilize globs:

==> exec.pl <==
#!/usr/bin/perl
use strict;
use warnings;
# You can omit this line, but there will be a warning about $My::Var being used only once
$My::Var = undef;
require 's1.pl';
require 's2.pl';
print $My::Var . "\n";

==> s1.pl <==
$My::Var = "Hello";


==> s2.pl <==
$My::Var .= "World";

Globs are basically entries in package stashes. Package variables and subroutines live inside a package stash; stash entries are called globs.

http://perldoc.perl.org/perlguts.html#Stashes-and-Globs

The relative simplicity of stashes and globs, and the ease to manipulate them is one of the things I think makes Perl really cool.

Upvotes: 1

amon
amon

Reputation: 57600

AFAIK it is not possible to have two variables always share the same value. Here are some Ideas that could help you:

Package variables:

{
   package test1;
   our $var;
   sub step1 {$var = "Hello"}
}
{
  package test2;
  our $var;
  sub step1 {$var .= " World!\n"}
}

test1::step1();
$test2::var = $test1::var;
test2::step1();

print $test2::var;

Comment: Ugly

References:

{
  package test1;
  our $varref;
  sub init {
    my ($ref) = @_;
    $varref = $ref;
  }
  sub step1 {$$varref = "Hello"}
}
{
  package test2;
  our $varref;
  sub init {
    my ($ref) = @_;
    $varref = $ref;
  }
  sub step1 {$$varref .= " World!\n"}
}

my $var = "";
test1::init(\$var);
test2::init(\$var);

test1::step1();
test2::step1();

print $var;

Comment: Better, but requires more code.

An extra shared module:

{
  package test::shared;
  our $var;
}
{
  package test1;
  sub step1 {$test::shared::var = "Hello"}
}
{
  package test2;
  sub step1 {$test::shared::var .= " World!\n"}
}

test1::step1();
test2::step2();
print $test::shared::var;

Comment: Has some advantages.

Explicit state

{
  package test1;
  sub step1 {
    my $state = @_;
    $state->{var} = "Hello";
    return $state;  # superfluous, but helps understanding
  }
}
{
  package test2;
  sub step1 {
    my $state = @_;
    $state->{var} .= " World!\n";
    return $state;  # superfluous, but helps understanding
  }
}

my $state = {};

$state = test1::step1($state);  # equiv: test1::step1($state), because of references
$state = test2::step1($state);

print $state->{var};

Comment: this is almost object oriented programming. I would prefer this pattern, as it is explicit about what shared is given when. Explicit state makes it easy to scale your application, in terms of multithreading and reentrancy.

Cost: expliciteness. verbose syntax.

Benefit: Reentrancy, clear train of thought via expliciteness.

Upvotes: 1

Related Questions