Scoping: my, our, local, state#

Inside a sub, four declarators control where a variable lives, how long it lives, and who can see it. Pick the wrong one and the sub leaks state, fails to capture properly in a closure, or quietly clobbers something the caller relied on.

Declarator

Scope

Lifetime

Typical use

my

lexical (the block)

until the block ends

the default; private locals

our

lexical alias to package

as long as the package

shared package globals with a short name

local

dynamic (the call tree)

until the block ends

temporarily change a special variable

state

lexical (the block)

program lifetime

per-sub persistent state, init once

my — lexical locals#

my is the everyday declarator:

sub greet {
    my ($name) = @_;
    my $message = "Hello, $name!";
    return $message;
}

The variables exist for the duration of the call, are private to the body, and are stored in the sub’s pad (one slot per declared lexical). They are not visible to callers, callees, or eval’d code that doesn’t textually nest inside the sub.

my variables are the only ones that close over correctly. Closures capture cells in the surrounding pad, and only my (and state) variables get pad cells.

our — package globals with a lexical alias#

package Counter;

sub increment {
    our $value;                  # alias to $Counter::value
    $value++;
    return $value;
}

our $x declares a lexical alias in the current scope to the package variable $Pkg::x. The variable itself is global. If two packages both our-declare $VERSION, they each get their own — our prefixes with the current package name.

Use our when:

  • You genuinely want a package-level shared variable.

  • You want to silence use strict 'vars'; complaints about a variable that should be a package global ($VERSION, @ISA, @EXPORT, %ENV aliases, …).

Do not use our to share state between subs in the same file. That’s what my at file scope is for:

package Counter;

my $value = 0;                   # private to this package's file
sub increment { ++$value }
sub get       { $value   }

local — dynamically-scoped temporary#

local does not declare a new variable. It saves the current value of an existing (typically global) variable, sets a new value, and restores the old value when the enclosing block exits — even on exception:

sub slurp {
    my ($path) = @_;
    open my $fh, '<', $path or die "open $path: $!";
    local $/;                    # slurp mode for this sub only
    return <$fh>;
}

Without the local, the caller’s $/ would be permanently clobbered. With it, the change is confined to the dynamic extent of slurp — including any subs slurp happens to call.

local is the right tool for almost every special-variable override ($/, $\, $,, $_, $@, signal handlers in %SIG). It is rarely the right tool for ordinary user variables — those want my.

For the full register, see local and the error-state and I/O variable pages, which list which specials want local-isation in which patterns.

state — initialise once, keep forever#

use feature 'state';

sub counter {
    state $n = 0;                # initialised once, ever
    return ++$n;
}

counter();                       # 1
counter();                       # 2
counter();                       # 3

state variables are lexicals that survive between calls. The initialiser runs the first time control reaches the declaration; subsequent calls skip it.

state is the right tool for:

  • Per-sub caches and counters where the cost of constructing the data dominates and you don’t want a closure factory.

  • One-time setup that depends on values not available at compile time:

    sub compiled_re {
        my ($pattern) = @_;
        state %cache;
        $cache{$pattern} //= qr/$pattern/;
        return $cache{$pattern};
    }
    

    (Note: this caches the first pattern only with a literal state of a single regex; the hash form generalises it.)

Closures: capturing surrounding my#

An anonymous sub captures every my (or state) variable from its surrounding scope that it textually references:

sub make_adder {
    my ($n) = @_;
    return sub {
        my ($x) = @_;
        return $x + $n;          # captures $n
    };
}

my $add5 = make_adder(5);
my $add9 = make_adder(9);

$add5->(3);                      # 8
$add9->(3);                      # 12

Each call to make_adder creates a fresh $n, and the returned closure references its own $n. Two calls produce two independent counters / adders / state machines.

The closure-over-loop-variable surprise#

my @subs;
for my $i (1, 2, 3) {
    push @subs, sub { $i };
}

print $_->(), "\n" for @subs;
# 1
# 2
# 3   — fresh $i each iteration: each closure sees its own

This is the correct behaviour with for my $i: every iteration declares a fresh $i, each closure captures its own.

The buggy shape is when $i is declared outside the loop:

my $i;
my @subs;
for $i (1, 2, 3) {               # NO `my` — same $i every iteration
    push @subs, sub { $i };
}

print $_->(), "\n" for @subs;
# 3
# 3
# 3   — all three closures share the one $i, and its final value is 3

Always declare loop variables with my. Closure capture follows the variable, not the value, and «same variable» vs «different variable» is decided at the my site.

Capturing our and package globals#

our aliases live for the whole package, so a closure capturing $Counter::value shares state with every other piece of code that touches $Counter::value. That’s almost always not what you want — closures over package globals are a sign that the design wants a my instead.

Pad lifetime#

Every active sub call has a pad, a slot per declared lexical. The pad is what my writes into and what closures hold a reference to. While a closure is alive, every pad it captures is alive — even if the originating call has long returned. This is how make_adder’s $n survives the call to make_adder itself.

See also#

  • my, our, local, state — perlfunc detail pages for each declarator.

  • @_ — the one variable that’s always present in a sub regardless of declarators.

  • Declaration — anonymous subs and the lexical my sub form.

  • Recursion — closure-based trampolines and __SUB__.

  • Special variables — almost every special wants local, not my.