--------------------------------------------------------------------
7.16: How do I create a static variable?
(contributed by brian d foy)
In Perl 5.10, declare the variable with "state". The "state" declaration
creates the lexical variable that persists between calls to the
subroutine:
sub counter { state $count = 1; $counter++ }
You can fake a static variable by using a lexical variable which goes
out of scope. In this example, you define the subroutine "counter", and
it uses the lexical variable $count. Since you wrap this in a BEGIN
block, $count is defined at compile-time, but also goes out of scope at
the end of the BEGIN block. The BEGIN block also ensures that the
subroutine and the value it uses is defined at compile-time so the
subroutine is ready to use just like any other subroutine, and you can
put this code in the same place as other subroutines in the program text
(i.e. at the end of the code, typically). The subroutine "counter" still
has a reference to the data, and is the only way you can access the
value (and each time you do, you increment the value). The data in chunk
of memory defined by $count is private to "counter".
BEGIN {
my $count = 1;
sub counter { $count++ }
}
my $start = counter();
.... # code that calls counter();
my $end = counter();
In the previous example, you created a function-private variable because
only one function remembered its reference. You could define multiple
functions while the variable is in scope, and each function can share
the "private" variable. It's not really "static" because you can access
it outside the function while the lexical variable is in scope, and even
create references to it. In this example, "increment_count" and
"return_count" share the variable. One function adds to the value and
the other simply returns the value. They can both access $count, and
since it has gone out of scope, there is no other way to access it.
BEGIN {
my $count = 1;
sub increment_count { $count++ }
sub return_count { $count }
}
To declare a file-private variable, you still use a lexical variable. A
file is also a scope, so a lexical variable defined in the file cannot
be seen from any other file.
See "Persistent Private Variables" in perlsub for more information. The
discussion of closures in perlref may help you even though we did not
use anonymous subroutines in this answer. See "Persistent Private
Variables" in perlsub for details.
--------------------------------------------------------------------
The perlfaq-workers, a group of volunteers, maintain the perlfaq. They
are not necessarily experts in every domain where Perl might show up,
so please include as much information as possible and relevant in any
corrections. The perlfaq-workers also don't have access to every
operating system or platform, so please include relevant details for
corrections to examples that do not work on particular platforms.
Working code is greatly appreciated.
If you'd like to help maintain the perlfaq, see the details in
perlfaq.pod.
Why would you want to do this? Would not a global variable suffice?
Or put another way, how would using a global variable fail but a
static variable fulfil a requirement.
Sorry if this is a basic question, but I just can't get my head around
it.
TIA
Owen
A global variable is visible and can be altered, well, globally, which
usually is A Bad Thing(TM).
A static variable is local to a specific subroutine and cannot be
accessed or changed outside of this sub, thereby ensuring that it still
has the same values as the last time the sub defined it instead of some
rouge piece of outside code.
jue
> Why would you want to do this? Would not a global variable suffice?
> Or put another way, how would using a global variable fail but a
> static variable fulfil a requirement.
One of your biggest tasks as a programmer is to limit the action of any
one bit of code to the smallest scope possbile so it only affects what
it should affect, and nothing else. That's true regardless of the
language you use.
Thank you, I don't have Perl-5.10, and on this 5.8.8. perldoc -f state
produces nothing
So it's time to install another Perl
Thank you
Owen
> I don't have Perl-5.10, and on this 5.8.8. perldoc -f state
> produces nothing
>
> So it's time to install another Perl
It always is,
but there are plenty of ways to create a static variable in a previous
Perl too.
Examples:
Alternative-1:
{ my $static;
sub a_sub_using_static {
# ...
}
}
The $static lives in in the "private environment" of the sub.
Alternative-2:
sub a_sub_containing_a_static {
my $static if 0;
# ...
}
The $static is properly created at compile time, but never reset at run
time.
--
Affijn, Ruud
"Gewoon is een tijger."
Eww. That makes for an interesting discussion point but please don't
encourage it. It's much to easy for an unwary programmer to extend the
idiom inappropriately, it's too clever for use in production code, and I
doubt that the current behavior is guaranteed to not change.
-mjc
> Owen schreef:
>
> > I don't have Perl-5.10, and on this 5.8.8. perldoc -f state
> > produces nothing
> >
> > So it's time to install another Perl
>
> It always is,
It's not time to install another Perl. Although you might have just
been glib with that remark, most people probably aren't looking at
constantly changing the plumbing:
* Find out if you really need or want the new features. before you
decide to upgrade. You should try to keep current, but you don't have
to rush.
* Don't install anything with .0 point release unless you're . So
for production stuff, wait until 5.10.1. Let other people experience
the pain of .0 releases.
* Don't wipe out your current Perl until you know the new Perl
doesn't somehow break whatever you've done.
Its use is discouraged, somewhere in Perl's docs. (I remember it but
couldn't find it)
This "evil" idiom is not likely to disappear, because it is used a lot,
so you should at least know of it. (to be able to read it)
I actually like it and see nothing wrong with it.
The condition can also be a constant:
$ perl -Mstrict -Mwarnings -MData::Dumper -Mconstant=DEBUG,0 -e'
sub show {
my $log = 1 if DEBUG;
# $log ||= $Config{LOG};
return print Dumper $log;
}
show;
'
$VAR1 = undef;
But see also `perldoc -q static`, which points to "Persistent Private
Variables" in perlsub.
Happily, I've never encountered it in the wild. As of 5.10, it provokes
a warning:
Deprecated use of my() in false conditional
> I actually like it and see nothing wrong with it.
If someone unfamiliar with the construct came across code that used it
he'd have little chance of figuring out what did. I can find no hint of
it in perlfunc, perlsyn, or perlsub. That should be reason enough. I
don't much mind clever code that uses documented behavior, but this is
way across the line even for me.
It turns out that I didn't even understand how/why this works. I thought
that it was a combination of the compile-time effect of my() (defining a
lexical scope for a variable name) with its runtime effect (memory
allocation and initialization; disabled by the false conditional, and
thus static) and auto-vivification (to allocate the memory for the first
usage since my() didn't do it). I was pondering what sort of quirk would
have caused auto-vivification to allocate the variable in the scratchpad
instead of the symbol table.
Then I read perldiag, which says:
There has been a long-standing bug in Perl that causes a lexical
variable not to be cleared at scope exit when its declaration
includes a false conditional. Some people have exploited this bug
to achieve a kind of static variable.
So there you have it. It's a bug. Use it at your own peril.
-mjc