my#
Declare one or more lexically scoped variables.
my introduces new variables whose visibility is bounded by the
enclosing block, file, or eval. The compiler records the
declaration at compile time; the storage is allocated and
(re)initialised each time control enters the scope. Unlike
local, my does not temporarily replace a package variable
— it creates a genuinely new variable that exists only while the scope
is live and is invisible outside it, including to any subroutines the
scope calls.
Synopsis#
my EXPR
my TYPE EXPR
my EXPR : ATTRS
my TYPE EXPR : ATTRS
A single variable may be written without parentheses; a list of two or more must be parenthesised:
my $x;
my ($a, $b, @rest);
my Foo $obj;
my $x : shared = 0;
What you get back#
my is a declaration, not a value-producing operator in the ordinary
sense. In rvalue position it yields its variable (or the list of
variables) as an lvalue you can assign to. The common idioms are:
my $x = $expr; # scalar context on RHS
my ($first, @rest) = @list; # list context on RHS; destructuring
my @copy = @src; # list context; @copy gets the elements
my %h = @pairs; # list context; pairs populate the hash
When no initialiser is given, each declared variable starts as
undef (scalar), empty list (array), or empty hash.
Scope and lifetime#
Block scope. A
myvariable is visible from the point immediately after its declaration to the end of the innermost enclosing block, file,eval,do,require, oruse’d file.Control-expression scope. The controlling expression of
if/unless/elsif/else,while/until,for/foreachis part of the scope of the declaration it contains. Inwhile (my $line = <$fh>) { ... }the variable$lineis live throughout the loop body and itscontinueblock, but not beyond.Fresh storage on every entry. Each time control re-enters the scope, the variable is created anew. This is the key difference from
state, which preserves its value across entries.Closures capture storage, not values. An anonymous sub created inside the scope keeps that particular instance of the variable alive for as long as the sub is reachable.
sub make_counter {
my $n = 0;
return sub { ++$n }; # closes over this $n
}
my $c = make_counter();
$c->(); $c->(); # 1, 2
List form and destructuring#
With parentheses, my supplies list context to the right-hand side
and destructures the result:
my ($sec, $min, $hour) = localtime;
my ($head, @tail) = @list; # @tail absorbs the rest
my ($x, $y) = ($y, $x); # swap via list assignment
Use undef as a placeholder to skip a position:
my (undef, $min, $hour) = localtime; # discard seconds
Without parentheses, my $foo is a single-variable declaration and
the comma operator applies to whatever follows:
my $foo, $bar = 1; # WRONG: declares $foo only;
# $bar is the package variable
my ($foo, $bar) = (0, 1); # Right.
Context traps#
my does not change how the right-hand side is evaluated — it
only modifies the variable on the left. A scalar my $foo imposes
scalar context; a parenthesised my (...) imposes list context:
my $line = <$fh>; # scalar context: one line
my ($line) = <$fh>; # list context: first of a list
my @lines = <$fh>; # list context: all remaining lines
The classic mistake is writing my ($foo) = <$fh> when a single
line was wanted — the parentheses turn on list context and the
filehandle returns a one-element list; the value happens to be the
first line, but the surrounding context is wrong for anything that
follows.
my vs local vs our vs state#
Four declarations, four different meanings:
my— introduces a new lexical variable. Not visible to called code. Fresh storage each entry.local— does not declare anything. It saves the current value of an existing package variable and restores it when the enclosing scope exits. Visible to called code through dynamic scope. Use it for the handful of magical globals ($_,$/,$\,$,,$|,%ENV, …) that cannot be lexicalised.our— declares a lexical alias for a package (global) variable. The storage lives in the package’s symbol table;ourjust lets you refer to it without the package prefix for the rest of the lexical scope. Satisfiesuse strict 'vars'.state— likemyin visibility, but the storage persists across re-entries to the scope. Initialisation runs once; subsequent entries leave the value alone.
package Counter;
our $total = 0; # package global; $Counter::total
my $cache; # lexical; invisible outside this file
state $calls = 0; # lexical; keeps its value across calls
sub tick {
local $\ = "\n"; # temporarily override output separator
++$calls;
print ++$total;
}
Critical point: my $var does not mask a package variable with
the same name. The package variable remains accessible through its
fully qualified form while the lexical is in scope:
package main;
our $x = 10;
my $x = 20;
print "$x and $::x\n"; # "20 and 10\n"
TYPE and attributes#
Both forms are part of the language but their semantics are still evolving (upstream wording).
TYPE — a bareword class name, a constant declared via
use constant, or__PACKAGE__. Historically bound to thefieldspragma; for ordinary use it serves as a hint and does not enforce a type at runtime.my Foo $obj = Foo->new;
ATTRS — a colon-introduced attribute list handled by the
attributespragma (andAttribute::Handlerssince 5.8.0).my $x : shared; my @buf : Locked;
See L<perlsub/”Private Variables via my()”> upstream for the authoritative wording.
Declaration is not yet in scope on its own RHS#
The newly declared variable is not visible until after the declaring statement finishes. That makes this idiom well-defined:
my $x = $x; # new $x initialised from the old $x
and this condition dependent on a pre-existing outer $x:
my $x = 123 and $x == 123; # false unless the old $x was 123
Within a single statement, any further mentions of the name refer
to the pre-declaration binding (or raise a strict 'vars' error if
no such binding exists):
our $x = 2;
foo($x, my $x = $x + 1, $x); # foo() receives (2, 3, 2)
Examples#
Typical subroutine entry — name the arguments:
sub distance {
my ($x1, $y1, $x2, $y2) = @_;
return sqrt( ($x2-$x1)**2 + ($y2-$y1)**2 );
}
Loop-local index with for my:
for my $i (1 .. 10) {
# $i is fresh each iteration; invisible after the loop
}
File-scoped private state — the variable exists for the life of the interpreter but is unreachable from outside this file:
my $cache = {};
sub lookup { $cache->{ $_[0] } //= _compute($_[0]) }
Private subroutine via a lexical coderef:
my $helper = sub { ... };
$helper->($x);
Shadowing warning — redeclaring in the same scope emits a
shadow-category warning under use warnings:
use warnings 'shadow';
my $x = 1;
my $x = 2; # warning: "my" variable $x masks ...
Edge cases#
Only alphanumeric identifiers. Magical built-ins such as
$/,$_,$\,%ENV,@ARGVcannot be lexicalised. Uselocalto scope them dynamically.No package qualification.
my $Foo::baris a syntax error:myvariables are not package-owned and cannot carry a::qualifier.Missing parentheses around a list.
my $a, $bdeclares only$a;$bis the package variable. Always parenthesise two or more names.List-context surprise.
my ($line) = <$fh>forces list context on the read; the RHS is a one-element list, not a scalar. Drop the parentheses if you want scalar semantics.foreachwithoutmy.for $i (...)localises$idynamically in the manner oflocal. Preferfor my $i (...)to confine the index lexically.Shadowing in loops. A
myinside a loop body declares a fresh variable every iteration. If that is unwanted (e.g. a counter that should survive iterations), declare it outside the loop or usestate.Closure capture. A closure over a
myvariable keeps that particular instance alive. Different calls to an enclosing sub produce independent closures over independent variables.use strict 'vars'interaction.mysatisfies strict-vars within its scope; variables without a declaration must beour, fully qualified, or predeclared withuse vars.Compile-time vs run-time. The name binding happens at compile time; the initialiser runs at run time, and re-runs on each scope entry. Expensive initialisers inside hot loops pay that cost every iteration.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
our— lexical alias for a package variable; satisfiesstrict 'vars'without creating new storagelocal— dynamically scoped save/restore of an existing package variable; the tool for magical globalsstate— lexical likemy, but storage persists across scope re-entriesundef— placeholder in a parenthesisedmylist, and the initial value of an uninitialised scalaruse strict— makesmy/our/ fully-qualified names mandatory, catching accidental globalsattributes— pragma that interprets the: ATTRSportion of amydeclaration