state#
Declare a lexically scoped variable whose value persists across calls to its enclosing subroutine.
A state variable has the same visibility rules as a my
variable — it is visible only inside the block that declares it —
but it is initialised exactly once per enclosing closure, not on
every entry to the block. This is Perl’s built-in way to write
persistent private variables: counters, memoisation caches,
one-time-computed lookup tables, anything you would otherwise hide
inside a file-scoped lexical above a sub.
Synopsis#
state $scalar
state $scalar = EXPR
state ($a, $b, undef, $c)
state @array
state %hash
state TYPE $var
state $var : ATTRS
What you get back#
state is a declaration, not a function. Like my it returns
the variable(s) it declares, so it can be used in any expression
position where the declared variable would appear:
(state $n //= 0)++; # declare-and-use in one expression
print ++(state $calls), "\n"; # count calls to this line
The initialiser on the right of = is evaluated only the first
time control flows through the declaration in that particular
closure instance. On every subsequent entry, the declaration
re-exposes the already-initialised variable and the initialiser is
skipped.
Persistence scope — what “once” means#
“Once per enclosing closure” is the precise rule. A state variable
lives as long as the CV (code value) that contains its declaration:
In a named sub, the CV is created once at compile time. The
statevariable is initialised on the first call and retains its value across every later call for the life of the process.In an anonymous sub / closure, each
sub { ... }evaluation produces a fresh CV with its own freshstateslot. Two closures made from the same source do not share state.In a nested block inside a sub, the
statestill belongs to the surrounding CV — it is not re-created on each entry to the inner block.
sub counter { state $n = 0; ++$n }
counter(); counter(); counter(); # returns 1, 2, 3
my $make = sub { sub { state $n = 0; ++$n } };
my $a = $make->();
my $b = $make->();
$a->(); $a->(); $b->(); # $a sees 1, 2; $b sees 1
Feature gate and availability#
state has always been feature-gated. Two ways to enable it:
use feature 'state';— turns on just this feature.use v5.10;(or any later version bundle, includinguse v5.36anduse v5.42) — implicit via the version feature bundle. Every modern program already hasstateavailable through itsuse vX.Yline.
Without the feature in scope, state is parsed as an ordinary
bareword. To reach the built-in unconditionally, write
CORE::state.
use v5.36; # 'state' feature is on by default
sub hits { state $n = 0; ++$n }
List declarations and initialisers#
state supports the parenthesised list form for declaring several
variables at once, with undef as a placeholder:
state ($x, $y, undef, $z);
What it does not yet support is initialising a list of
state variables. Upstream explicitly notes this: initialisation
of state variables in a parenthesised list is not currently
possible, so the list form is useful only for declaration.
Aggregates — state @array and state %hash — have historically
had the same restriction on initialisers (Perl emitted an
experimental warning, and in several versions a syntax error, for
state @a = (1, 2, 3)). Build the aggregate inside the body
instead:
sub primes_below_100 {
state @p;
unless (@p) {
@p = _sieve(100); # fill on first call only
}
return @p;
}
The unless (@p) / unless (%h) idiom above is the portable
replacement for an aggregate initialiser.
Declaration placement and same-statement semantics#
Like my, our, and local, a state
declaration can appear anywhere an expression is allowed (except
inside string interpolation). The new binding takes effect for
subsequent statements, not for other mentions of the same
variable in the same statement:
package main;
use feature 'state';
our $x = 2;
foo($x, state $x = $x + 1, $x); # foo() receives (2, 3, 2)
foo($x, $main::x); # foo() receives (3, 2)
The first $x and the trailing $x in the same call still refer
to our $x; only the next statement sees the state $x.
Examples#
A hit counter — the canonical one-liner:
sub hits { state $n = 0; ++$n }
hits(); hits(); hits(); # returns 1, 2, 3
Memoisation of an expensive pure function:
sub fib {
my ($n) = @_;
state %cache;
return $cache{$n} //= $n < 2 ? $n : fib($n-1) + fib($n-2);
}
Lazy one-time setup of a read-only table:
sub months {
state @m = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
return @m;
}
Here the initialiser is a simple list, which works because the RHS
of state @m = ... is constant-folded to a list literal and
current Perl permits this form; the more general case of a
computed list still wants the unless (@m) { ... } pattern above
for portability.
Per-closure state (fresh slot per sub { ... } evaluation):
sub make_counter {
return sub { state $n = 0; ++$n };
}
my $a = make_counter();
my $b = make_counter();
$a->(); $a->(); # 1, 2
$b->(); # 1 — independent of $a
Declare-and-use in a single expression:
while (my $line = <$fh>) {
warn "first line was: $line" if (state $first //= $line) eq $line;
}
Edge cases#
Aggregate initialisers.
state @a = (1, 2, 3)andstate %h = (k => 1)have a long history of being restricted or experimental. When in doubt, declare the aggregate and fill it underunless (@a) { ... }on the first call. Scalar initialisers (state $x = EXPR) have always been fine.Same-statement reuse. A fresh
statedeclaration does not apply to other mentions of the same name within the same statement; those still resolve to whatever was in scope before the declaration. See thefoo($x, state $x = $x + 1, $x)example above.Shadowing warning. Redeclaring the same name in the same scope —
state $n; state $n;— shadows the first. Underuse warningsthis emits a warning in theshadowcategory. Almost always a bug.Anonymous-sub multiplicity. Every evaluation of
sub { ... }produces a new CV with its ownstateslot. If you build many closures from the same source, each has its own independentstate— that is a feature, but it surprises people expecting file-scoped persistence.Threads and forks.
statelives in the CV, which is cloned onfork(copy-on-write in the OS sense — each process continues with its own copy) and onthreads->create(deep-cloned). Two processes or threads do not share astatecounter.localdoes not apply.statevariables are lexicals, not package variables, solocalcannot save and restore them. Wrap the whole sub in its own scope or use a different mechanism if you need dynamic scoping.Access via
CORE::state. When writing code that must parse even without the feature enabled, prefix the keyword:CORE::state $n = 0;.Destruction.
statevariables live as long as the CV. For a named sub in the main program that means “until global destruction.” Do not put a file-handle or a large buffer in astatevariable expecting it to be freed at sub exit — it will not be.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
my— ordinary lexical; reinitialised on every block entry, the natural contrast tostateour— lexical alias for a package variable; use when callers need to see orlocal-ise the valuelocal— dynamic scoping for package variables; orthogonal tostateand cannot be applied to itsub—statelives inside a CV; understanding how named vs anonymous subs differ explains per-closure stateuse—use v5.10and later enable thestatefeature as part of the version bundleundef— legal placeholder insidestate (...)list declarations