UBB.Dev
Posted By: Dave_L Loading a package from another package - 10/08/2003 5:21 AM
[Perl 5.8.0]

Code
package A
...
use B;
...
print $B::var; <<< error
...
Is there some trick to "use"ing one package from within another package?

Variables defined within B don't seem to be accessible within A, although they are accessible from the main namespace in the file that "use"s A.
Depends on how $B::var was declared...

Code
package B;
use strict;
my $nope = 0;
our $maybe = 1;
use vars qw($probably);
$probably = 1;

package A;
use strict;
print $B::probably;
print $B::maybe;
print $B::nope;
This ends up printing "11"... no zero. No error either.

Thus: Stuff that's really supposed to be shared by package B will be shared. %)

Can you give a little more detail on what you're trying to do, and how it's failing to work?
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 6:11 AM
Thanks smile

I was declaring the variable using "my" within the package, which I suppose hid it from being referenced outside the package. I changed it to "our", and it works now.

I was never fully clear on exactly what "our" does, although I've read the manual's description of it many times.

Here's my application:

I have a package MyDefs.pm that I'm using to define config variables that other packages will reference.

Here's part of it:

Code
package MyDefs;

use strict;
use warnings;
use re 'taint'; # suppress untainting by regexes

# paths
our $home_dir = 'c:';
our $dest_base_dir = "$home_dir/backup";
our $lock_filename = $dest_base_dir/backup_lock";
our $list_filename = 'backup.lst';
Then in other packages, I reference the variables like this:

Code
use MyDefs();
open(my $fh_lock, '>', $MyDefs::lock_filename) or die "open: $!";
Does that seem like reasonable coding practice?

I had forgotten how complicated Perl is, compared to PHP. frown
Well, personally I'd just use a hash... if a module was needed, the hash would just get exported via Exporter.

Perl is only as complicated as you want to make it. wink

my creates a var usable within the current scope. If a var is my'd from inside a file, but not inside a sub, then it's available from everything inside that file. The var can't be accessed from outside of that file, in that case.

our is the same, but it allows outside access in many cases. However, I avoid our completely, as it requires 5.6+ and tends to do unintended/spooky things. All of my vars that need to be globals are done so via use vars.
Posted By: Burak Re: Loading a package from another package - 10/08/2003 6:04 PM
Well... I prefer objects and object tables as data fields smile

shortly: our() creates global class variables while my() creates private variables.

And a Quote from Damian Conway' s OOPerl Book:

Quote
quote:

It may help to think of the two types of variables-package and lexical-in the way the Ancient Greeks thought of their gods. Ancient Greece had big general-purpose gods like Uranus, Zeus, Aphrodite, and Atropos, who existed for all time and could appear anywhere without warning. These are analogous to package variables*.

Then there were the small, specialized gods like the spirits of trees, or doorsteps, or hearths. These gods were restricted to a well-defined domain-a tree, a building, the fireplace -and existed only for a specific period-the life of the tree, the occupation of the building, the duration of a fire. These are like lexical variables: localized and transient.

*The big Greek gods even came in "packages": $Titans::Uranus, $Olympians::Zeus, $Olympians::Aphrodite, $Fates::Atropos.
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 6:43 PM
Is "use vars" safe to use? The current Perl documentation says that's obsolete, and "our" is supposed to be used instead.

My interpretion of "our" is that it's roughly analogous to "extern" in C/C++. I.e., it doesn't allocate space for a variable, but rather brings a variable defined elsewhere into the current scope. But I'm not sure if that's really accurate.

To refresh my memory, I dug out an old Perl script I wrote a couple of years ago to see how I handled this situation. Here's an extract that illustrates the method. Some of this I had to figure out by trial and error, and may not be the best way of doing it.

fsConfig.pm - configuration module - defines class fsConfig

Code
package fsConfig;

use strict;
use re 'taint';

# constants
use constant MAX_ID => 999_999; # warning - don't change this
use constant FTP_TIMEOUT => 15; # seconds
use constant MAX_SEARCH_RESULTS => 100; # max number of items returned by search

# class constructor
sub load {
my $invocant = shift;

my $self = {
...
'submissions_mode' => 'restricted',
...
};

my $class = ref($invocant) &#0124;&#0124; $invocant;
return bless($self, $class);
}

# accessor methods

...

sub submissions_mode {
my $self = shift;
return $self->{'submissions_mode'};
}

...

1;
main.cgi - example module that accesses configuration parameters

Code
#!/usr/bin/perl -wT

use strict;
use re 'taint'; # suppress untainting by regexes

use fsConfig();

# instantiate configuration object and store it in a global variable
$::Config = fsConfig::->load() or die 'Failed to load configuration data';

# suppress warning 'name used only once' (?)
our $Config;

...

# example of accessing configuration constant:
print "The FTP-timeout parameter is " . $Config->FTP_TIMEOUT . "n";

# example of accessing configuration variable:
print "The submissions-mode is " . $Config->submissions_mode() . "n";

...
Critique is welcome smile
Posted By: Burak Re: Loading a package from another package - 10/08/2003 6:55 PM
you can use anything until you see "deprecated" smile

also if you dont care about archaic perl distributions you can use it...
Wow... you're playing with the :: namespace directly. That takes guts...
Posted By: Burak Re: Loading a package from another package - 10/08/2003 7:40 PM
uhm... it's not different than $Config = foo if you're under the main package...

But, $::Config & then our $Config is not meaningfull... it must be our $Config = foo...
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 7:56 PM
My understanding is that $::Config is equivalent to $main::Config, and is necessary to make the variable global, so that it's available to any other modules that are "use"-d by the main.cgi module.

The above code works. That's what I meant by having to resort to trial and error. smile

I remember having to do some experimention to come up with that. But I'll play around with it some more.
$::Config exists in the core namespace... only things that are generally considered to be magic live there, as they get inherited into everything.

$main::Config is a completely different namespace...
Posted By: Burak Re: Loading a package from another package - 10/08/2003 8:35 PM
dont think so. :: is the package main. you can also use it like main::. It has nothing to do with CORE

http://www.perldoc.com/perl5.8.0/pod/func/package.html

Quote
quote:

If the package name is null, the main package as assumed. That is, $::sail is equivalent to $main::sail (as well as to $main'sail, still seen in older code).

Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 8:41 PM
Hmmmm ....

"If the package name is null, the main package is assumed. That is, $::sail is equivalent to $main::sail."

Programming Perl, 3rd Edition, p. 291.

Also stated at http://perldoc.com/perl5.8.0/pod/perlmod.html#Packages

Is that incorrect?

----
Edit : Burak posted the same thing while I was in the process of posting this. I would delete this post, but don't have access to do so. wink
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 8:52 PM
Quote
quote:
Originally posted by Burak:
But, $::Config & then our $Config is not meaningfull... it must be our $Config = foo...
The only reason I added "our $Config" was to suppress warning messages like these that occur for references to $Config:

Variable "$Config" is not imported at main.plx line 15.
Global symbol "$Config" requires explicit package name at main.plx line 15.


Do you mean that "our $Config" should be replaced with "our $Config = $::Config" ?

That works too, but it doesn't appear to matter which one of those I use, the code executes the same way. But like I said, I don't fully understand "our". smile

P.S. I just checked, and other modules that are "use"-d by main.cgi have the following, so I see what you're saying:

Code
our $Config = $::Config;
Posted By: Burak Re: Loading a package from another package - 10/08/2003 8:58 PM
no. I'm saying this:

our $Config = fsConfig->load() or die '...';
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 9:09 PM
Ok, but ...

$Config is intended to be a global variable, initialized in main.cgi, and accessible by other modules that are "use"-d by main.cgi. How would the other modules access $Config?
Posted By: Burak Re: Loading a package from another package - 10/08/2003 9:39 PM
as $::Config or $main::Config if you have to call it inside a module.

I've tested your code like this:

Code
#!/usr/bin/perl -w
use strict;
use CGI ();
$::Config = CGI->new;
our $Config;

require "req.pl";
require Req;

package Test;

printf "Test: %s-%sn", ref($Config),ref($::Config);
req.pl

Code
printf "req: %s-%sn", ref($Config),ref($::Config);

1;
Req.pm:
Code
package Req;
printf "Req: %s-%sn", ref($Config),ref($::Config);

1;
output:

Quote
quote:

req: CGI-CGI
Req: -CGI
Test: CGI-CGI
inside a file you can use it in all packages, but if you use() or require() a module you cant... It also works on simple code files...
Posted By: Dave_L Re: Loading a package from another package - 10/08/2003 11:31 PM
So you're defining the global as
Code
$::Config = CGI->new;
our $Config;
rather than as
Code
our $Config = CGI->new;
.

I can see that the former would work. It was the attempt to use the latter that I didn't understand.
Posted By: Burak Re: Loading a package from another package - 10/08/2003 11:37 PM
no. I'm testing your sample code to see the behaviour smile As you can see your usage fails when you call a module outside...

I mean you have to use it like $::Config to be sure...
Posted By: Burak Re: Loading a package from another package - 10/08/2003 11:38 PM
sorry, I wasnt clear about the code I wrote...
Posted By: Dave_L Re: Loading a package from another package - 10/09/2003 7:58 AM
Burak & Charles:

Thanks for your help. I think I've re-familiarized myself with Perl adequately for the time being. smile

For what I'm doing now, I didn't really need global "variables", but only constants, so I've set up the config module like this:

Code
package MyDefs;

...
use constant DEST_BASE_DIR => 'c:/backup';
use constant LOCK_FILENAME => "@{[DEST_BASE_DIR]}/backup_lock";
use constant LIST_FILENAME => 'backup.lst';
use constant CMD_FILENAME => 'backup.cmd';
...

1;
Then in other modules, I can reference the constants like this:

Code
...
use MyDefs();
...
open(my $fh_lock, '>', MyDefs::LOCK_FILENAME);
...
my $cmd = "$dest_dir/@{[MyDefs::CMD_FILENAME]}";
...
That works, though I still think you should be using Exporter... that way you could use MyDefs and get LOCK_FILENAME and the rest just plain imported.
Posted By: Dave_L Re: Loading a package from another package - 10/09/2003 8:17 AM
If you mean so that I wouldn't have to qualify the constants (LOCK_FILENAME instead of MyDefs::LOCK_FILENAME), I prefer specifying the package name in the references. I think that it reduces the likelihood of name collisions. wink
© UBB.Developers