Namespace And Separate Modules

H

Hal Vaughan

I'm having a problem understanding namespace with modules. If I have a
program and it uses some modules (say mod1, mod2, and mod3), I thought that
the names I export from those modules are available in the main program's
namespace -- and ONLY in that program's namespace.

I also was under the understanding that any variables global to, say, mod2,
when set from the main program, would ONLY be set in that "instance" of
mod2. So if, for example, mod1 also used mod2 (with a separate "use mod2;"
statement within mod1), any global variables set in the main program's
instance of mod2 should be in a completely different namespace from the one
within mod1, where mod1 uses mod2. In other words, while both the main
program and mod1 use mod2, the program's mod2 should maintain variables
separately from mod1's mod2.

However when I run tests, that is not the case (code and sample run included
below). When I test it, if I make changes in the main program's mod2, they
show up in mod1's mod2, and vice versa. For me, this is actually a
benefit, but it is not how I understood namespace to work.

Is this the behavior I should expect? Is it documented or intended, so I
can count on it always happening? If I use a module (say mod1) in the main
program, will, and use a number of other modules from the main program, if
any of those other modules use mod1, will the variables in each instance of
mod1 stay consistant with each other?

Thanks for any comments. This is rather difficult for me to follow and make
sure I understand it correctly.

Hal
----------------------------------------------------------------------
Program code:

#!/usr/bin/perl
use fakemods::mod1;
use fakemods::mod2;
use fakemods::mod3;
print "This is the main program\n";
setval1(1); printval1();
setval12(2); printval2();
setvalx12(3); printval2(); printvalx12();
setval2(4); printval2(); printvalx12();
----------------
fakemods/Mod1.pm listing:

package fakemods::mod1;
use Exporter;
use fakemods::mod2;
use strict;
our ($mainval);

BEGIN {
use vars qw(@ISA);
@ISA = qw(Exporter);
our @EXPORT = qw(setval1 printval1 setval11 setval12 setval13
setvalx12 printvalx12);
}
sub setval1 {
$mainval = $_[0];
return;
}
sub printval1 {
print "Value 1: $mainval\n";
return;
}
sub setval11 {
my $val = shift(@_);
main::fakemods::mod1::setval1($val);
return;
}
sub setval12 {
my $val = shift(@_);
main::fakemods::mod2::setval2($val);
return;
}
sub setval13 {
my $val = shift(@_);
main::fakemods::mod3::setval3($val);
return;
}
sub setvalx12 {
my $val = shift(@_);
setval2($val);
return;
}
sub printvalx12 {
printval2();
return;
}
1;

----------------
fakemods/Mod2.pm listing:

package fakemods::mod2;
use Exporter;
use strict;
our ($mainval);
BEGIN {
use vars qw(@ISA);
@ISA = qw(Exporter);
our @EXPORT = qw(setval2 printval2 setval21 setval22 setval23);
}
sub setval2 {
$mainval = $_[0];
return;
}
sub printval2 {
print "Value 2: $mainval\n";
return;
}
sub setval21 {
my $val = shift(@_);
main::fakemods::mod1::setval1($val);
return;
}
sub setval22 {
my $val = shift(@_);
main::fakemods::mod2::setval2($val);
return;
}
sub setval23 {
my $val = shift(@_);
main::fakemods::mod3::setval3($val);
return;
}
1;
----------------
fakemods/Mod3.pm listing:

package fakemods::mod3;
use Exporter;
use strict;
our ($mainval);
BEGIN {
use vars qw(@ISA);
@ISA = qw(Exporter);
our @EXPORT = qw(setval3 printval3 setval31 setval32 setval33);
}
sub setval3 {
$mainval = $_[0];
return;
}
sub printval3 {
print "Value 3: $mainval\n";
return;
}
sub setval31 {
my $val = shift(@_);
main::fakemods::mod1::setval1($val);
return;
}
sub setval32 {
my $val = shift(@_);
main::fakemods::mod2::setval2($val);
return;
}
sub setval33 {
my $val = shift(@_);
main::fakemods::mod3::setval3($val);
return;
}
1;

Test output:
----------------
[hal@workstation:~]$ modtest
This is the main program
Value 1: 1
Value 2: 2
Value 2: 3
Value 2: 3
Value 2: 4
Value 2: 4
 
N

nobull

Hal said:
I'm having a problem understanding namespace with modules. If I have a
program and it uses some modules (say mod1, mod2, and mod3), I thought that
the names I export from those modules are available in the main program's
namespace -- and ONLY in that program's namespace.

No, exporting symbols creates aliases. A symbol exported from mod1 to
main makes an entry in the main:: symbol table that points to exactly
the same place as the one in the mod1::.
I also was under the understanding that any variables global to, say, mod2,
when set from the main program, would ONLY be set in that "instance" of
mod2.

No, you are way off track. In the normal course of events there is no
concept of "instance" unless you create obejcts.
So if, for example, mod1 also used mod2 (with a separate "use mod2;"
statement within mod1), any global variables set in the main program's
instance of mod2 should be in a completely different namespace from the one
within mod1, where mod1 uses mod2.

No, you are way off track. That said Perl is sufficiently flexible
that you _could_ create a mod2 with those semantics by providing your
own custom import() method.
Is this the behavior I should expect?
Yes

Is it documented or intended,
Yes

so I can count on it always happening?

Unless the author of mod2 decides otherwise.
If I use a module (say mod1) in the main
program, will, and use a number of other modules from the main program, if
any of those other modules use mod1, will the variables in each instance of
mod1 stay consistant with each other?

Unless the author of mod1 decides otherwise.
 
S

Sherm Pendley

Hal Vaughan said:
I'm having a problem understanding namespace with modules. If I have a
program and it uses some modules (say mod1, mod2, and mod3), I thought that
the names I export from those modules are available in the main program's
namespace -- and ONLY in that program's namespace.

I also was under the understanding that any variables global to, say, mod2,
when set from the main program, would ONLY be set in that "instance" of
mod2.

There is only one "instance" of a given name space. Importing symbols from a
name space into another doesn't make copies of the original's data, it uses
typeglobs to create aliases that refer to the same variable.
However when I run tests, that is not the case (code and sample run included
below). When I test it, if I make changes in the main program's mod2, they
show up in mod1's mod2

There is only *one* mod2.

Have a look at "perldoc perlmod", especially the section titled "Symbol Tables"
for details about how symbols are imported by Exporter.pm. In a nutshell, when
you do this:

*main::foo = \$mod2::foo;

$main::foo and $mod2::foo are now two different names for the *same* variable.

sherm--
 
H

Hal Vaughan

No, exporting symbols creates aliases. A symbol exported from mod1 to
main makes an entry in the main:: symbol table that points to exactly
the same place as the one in the mod1::.


No, you are way off track. In the normal course of events there is no
concept of "instance" unless you create obejcts.


No, you are way off track. That said Perl is sufficiently flexible
that you _could_ create a mod2 with those semantics by providing your
own custom import() method.


Unless the author of mod2 decides otherwise.


Unless the author of mod1 decides otherwise.

I think I've got it, but let me try another example (this is so different
from what I expected I want to be sure I've got it). Say I have a program
that uses MyMods::Log and MyMods::process. Inside MyMods::process I also
use MyMods::Log. There is a function in MyMods::Log that goes like this:

sub dolog {
my $msg = $_[0];
#$logfile is a global variable, set by the original program on startup
open(LOG, ">$logfile");
print LOG "$msg\n";
close LOG;
return;
}

Now, if I understand you correctly, when the program sets $logfile, which is
a global variable in MyMods::Log (but it isn't exported), when I call
dolog() from inside MyMods::process, $logfile will have the same value as
when it is called from the original program. So any module the program
uses can call dolog() and it will write to the same file as long as I have
"use MyMods::Log" in that module. I don't have to specify or do anything
to make sure they all log to the same file -- that is a feature of Perl.

Is that correct?

Hal
 
J

Joe Smith

Hal said:
I think I've got it, but let me try another example (this is so different
from what I expected I want to be sure I've got it). Say I have a program
that uses MyMods::Log and MyMods::process. Inside MyMods::process I also
use MyMods::Log.

You have to understand two things.
1) Perl uses %INC to keep track of which modules have been loaded
so each on is only loaded once. To see a typical %INC, try this:
bash% perl -MFile::Find -le 'print "$_ = $INC{$_}" for sort keys %INC'

2) The 'use' statement tells Perl to load the module if it has not
already been loaded, then call the module's import() function. The
import() function causes aliases to be made in the current namespace
for variables defined in the used module.

In file MyProg.pl:
package main;
use MyMods::Log;
$logfile = "test.log";

In file MyMods/Process.pm:
package MyMods::process;
print $logfile;

In this case, $main::logfile, $MyMods::Log::logfile, and
$MyMods::process::logfile are entries in three different
symbol tables that point to the exact same variable.

As for code references, the variables accessable to the
function are the ones visible when the code was parsed.
It makes no difference whether you call it as
main::dolog(), MyMods::Log::dolog(), or MyMods::process::dolog();
the dolog() function will have at its disposal the same
variables in each case.
-Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top