CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
Accessing package variables?

 



jc1742
New User

Jul 27, 2011, 2:23 PM

Post #1 of 11 (4241 views)
Accessing package variables? Can't Post

I thought I knew this, but it turns out I don't. The perlmod page claims that it's possible to reference the local variables of a package (or module). I have a situation where it would be really handy to do this rather than writing a zillion subs, one per variable. But my attempts to do it have all failed, convincing me that I just don't know the syntax.

Here's a test program that I made up out of the task, stripped down to the minimum:



#!/usr/bin/perl -w
$A1 = new A;
$A2 = new A;
print "A1's x is " . $A1::x . "\n";
print "A2's x is " . $A2::x . "\n";
$A1->setx(11);
$A2->setx(22);
print "A1's x is " . $A1::x . "\n";
print "A2's x is " . $A2::x . "\n";
exit 0;
# # # # # # # # # # #
package A;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(x);
local $x='1';
sub new {bless{}}
sub setx {$O = shift; my $v = @_;
print "setx: x='$x' v='$v'\n";
$x = $v;
print "setx: x='$x'\n";
}

This is running on "perl, v5.8.8 built for i486-linux-gnu-thread-multi", on a Debian box, but it fails the same way on a nearby FreeBSD and an OSX system. Also, I've spent the day going through zillions of variants of the code, using syntax that seems to be implied by various man pages. But nothing I've tried has worked at all.

What I'd like the above code to do is print the values of the package's variable $x without going through a "get" subroutine. It'd also be nice if I didn't actually need the setx function, though the current app doesn't require that.

It seems like I have to be missing something that should be really obvious. But I can't find any example of code doing this. I only find claims that it's doable, without any code showing the syntax.

(The preview wipes out the indentation in the example, and experimenting finds no way to make the indentation work. Sigh. ;-)


FishMonger
Veteran / Moderator

Jul 27, 2011, 2:58 PM

Post #2 of 11 (4237 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

You need to use the code tags to retain the indentation.

Start by always including the stirct and warnings pragams in all of your scripts and declare all vars.

It's rarely a good idea to do what you want, but when it's appropriate, you'll want to declare $x as a global var, which is done with the 'our' keyword.

Code
our $x = 1;

Then you can access it with its fully qualified name $A::x

Prior to that, you'll need to load the module.

Code
use A;



(This post was edited by FishMonger on Jul 27, 2011, 3:00 PM)


jc1742
New User

Jul 27, 2011, 5:30 PM

Post #3 of 11 (4231 views)
Re: [FishMonger] Accessing package variables? [In reply to] Can't Post

Declaring $x global doesn't make sense to me. Note the important point here: The code has more than one instance of the package. The "new A" command is done twice in my stripped-down example (and more than twice in the real program). Each instance of A needs its own local copy of its variables, because they hold different values in the different instances.

My original code did have the "use strict" and "use warnings" commands, and it loaded the package from a different file via a "use" command. I'd stripped these out in my attempt to produce a minimal example of what I hadn't been able to make work right. I tossed everything that didn't seem to be strictly related to the topic at hand, which was getting at a package's local variables from outside the package. The "man perlmod" page says this is possible: "You can refer to variables and filehandles in other packages by prefixing the identifier with the package name and a double colon: $Package::Variable. I did this in my example, and it doesn't work at all. I also tried '->' instead of '::', which failed in exactly the same way. I tried other likely syntaxes, which I won't bother people with because they also failed.

I'm not trying to get the usual lecture on good programming style, and I'm not about to post an entire program with thousands of lines; I'm trying to learn the correct syntax for one tiny little detail of the language.

(It's possible that perl doesn't permit a package declaration as in my example, inside the same source file as its invocation. But I did have it in a separate "A.pm" file originally, and it failed exactly as my stripped-down example does. Also, the package name was longer than "A" originally; I stripped that down, too. ;-)


FishMonger
Veteran / Moderator

Jul 27, 2011, 5:56 PM

Post #4 of 11 (4228 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

Reducing your example to a minimal level is good and appreciated, but you still should always include the strict and warnings pragmas, in part because there are very important differences between what is allowed and not allowed.

One problem I see is that you're intermixing OO and functional style interfaces, which certainly can be done, as is is done in the CGI module, but shouldn't be done until you're fluent in both.

I need to work on cooking dinner, but when I have more time, I'll post one or two examples, unless someone else chimes in and provides those examples.


FishMonger
Veteran / Moderator

Jul 27, 2011, 7:57 PM

Post #5 of 11 (4203 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

Assuming you want to stay with the OO interface, your first decision to make is do you want to have a single var that all objects share, or do you want an independent var for each object.

If you want a shared var, then you need to declare it as a global var and either access it via its fully qualified name. If you want an independent var for each object, then declare it as a lexical as part of the object.

Here's an example of the shared version.

Example.pm

Code
package Example; 

use strict;
use warnings;

our $example = 'example';

1;


example.pl

Code
#!/usr/bin/perl 

use strict;
use warnings;
use Example;

print $Example::example;



jc1742
New User

Jul 27, 2011, 8:43 PM

Post #6 of 11 (4183 views)
Re: [FishMonger] Accessing package variables? [In reply to] Can't Post

The main reason I got into this is that the app I'm working on needs a lot of copies of the data structures, each with its own value for its local variables.

That was the main point of my stripped-down example. I called "new A" more than once, and stuffed the resulting references into the variables $A1 and $A2. Then I called $A1->setx() and $A2->setx() to stuff two different values into the two A objects' variables, both named $x (or $A::x presumably). Then I tried to use the values of these two different $x variables in the two instances of A.

If I can figure out how to do that right, I can probably implement what I'm trying to implement. The app I'm working on definitely needs to have many copies of its data structures, each describing a small part of the data, and linked together in complex ways. I'm having trouble finding documentation with coherent descriptions of how to do this right.


FishMonger
Veteran / Moderator

Jul 28, 2011, 8:07 AM

Post #7 of 11 (4091 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

Your new sub needs to declare and assign default values to the vars (which is typically done via a hash ref) and then return the blessed hash ref. The new sub could also accept args, i.e., a hash ref, containing the desired values to be put into the object. Then you need to write accessor/mutator subs which retrieve and/or set the vars.

See the following perldocs.
perlboot Perl OO tutorial for beginners
perltoot Perl OO tutorial, part 1
perltooc Perl OO tutorial, part 2
perlbot Perl OO tricks and examples


(This post was edited by FishMonger on Jul 28, 2011, 8:09 AM)


jc1742
New User

Jul 28, 2011, 1:46 PM

Post #8 of 11 (4056 views)
Re: [FishMonger] Accessing package variables? [In reply to] Can't Post


Quote
Then you need to write accessor/mutator subs which retrieve and/or set the vars.


So you're saying that what I asked about can't be done? ;-)

Adding the cpu cost of a function call to a simple variable reference is a rather large price to pay for something that, in most other language, has no time overhead. Thus, in C or C++, referencing a named field in a struct or class has no such overhead. The equivalent in perl seems to be accessing a named local variable in a package. If that requires a function ("method") call, it's a huge performance hit.

Also, if this is necessary, it sorta shoots down the primary reason for exporting variables. Of what value is exporting if one still needs access subs within the package to get/set those variables' values?

I'm clearly missing something about perl's OO/package design here ... ;-)

But I'll point out again that the "man perlmod" page disagrees; in its first paragraph it states "You can refer to variables and filehandles in other packages by prefixing the identifier with the package name and a double colon: $Package::Variable." The reason I asked my question in the first place was that I tried exactly this (where the $Package was the value returned by one of two "new A" calls), and it failed. I also tried it with '->' in place of '::', and that failed the same way. The call on each package's newx sub worked, in a sense, showing that my test package was defined and the syntax works for subs. It just fails for simple variables, contrary to what "man perlmod" says.

So did the "man perlmod" page lie to me about this? (If so, how can we punish the culprit that wrote that passage? ;-) If not, I'm at a loss as to where to go next.

But I'll read some more of those docs. Several of them have names that are new to me. I wonder where I might have found references to perltooc or perltoot? They're not names that I'd have guessed to try, and aren't mentioned in my "man perl" overview page.


FishMonger
Veteran / Moderator

Jul 28, 2011, 2:08 PM

Post #9 of 11 (4052 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

I'm about to go into a meeting, so I can't address your comments in any detail until I get off work.

What I can say is that your understanding of the docs is not correct, in part because you're intermixing the meanings and usage of Perl OO and functional modules. Perl OO modules don't, or at least shouldn't, export anything. Functional modules do export their subs and in some cases their global vars.

The example I provided shows you how to access package global vars in a non OO module using their fully qualified name, as you want to do.

For a listing of the available perldocs see this:
perldoc perl

or on line at http://perldoc.perl.org/


FishMonger
Veteran / Moderator

Jul 28, 2011, 5:52 PM

Post #10 of 11 (4022 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

Ok, I'm home now, but need to keep this short because I need to cook dinner.


Quote
So you're saying that what I asked about can't be done? ;-)

No, that's not what I'm saying, but directly accessing/modifying a variable in a Perl OO module is discouraged in part because it breaks encapsulation.

Yes, executing a method call does have a very small overhead and in most cases that overhead is very negligible, unless you're planning on calling the same method millions of times to access the exact same data and if you're doing that, you have a problem with code logic.

Here is a minimal example of an OO module approach that does what you what.

Example.pm

Code
package Example; 

use strict;
use warnings;

sub new {
my ($class) = @_;

bless {
var1 => 'var one',
var2 => 'var two',
var3 => 'var three',
}, $class;
}

1;


example.pl

Code
#!/usr/bin/perl 

use strict;
use warnings;
use Example;

my $obj = Example->new;

print $obj->{var3}, $/;

$obj->{var3} = 'new value';
print $obj->{var3}, $/;



(This post was edited by FishMonger on Jul 28, 2011, 5:53 PM)


FishMonger
Veteran / Moderator

Jul 28, 2011, 6:03 PM

Post #11 of 11 (4020 views)
Re: [jc1742] Accessing package variables? [In reply to] Can't Post

I should add that the best reference book that I've read on this subject is "Object Orientated Perl" by Damian Conway.
http://books.perl.org/book/171
http://www.amazon.com/Object-Oriented-Perl-Comprehensive-Programming/dp/1884777791

It is a little on the old side (circa 1999) but a very important reference book that you should read.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives