Default variables#

Two variables hold the implicit operands of Perl. $_ is the default scalar that countless built-ins read when called without an argument. @_ is the argument array of every subroutine. Together they account for most of the ”where did that value come from?“ surprises in Perl code.

$_ — the default scalar#

$_ is the topic: the value being talked about right now. A huge swath of Perl’s built-ins consult it when called with no explicit argument:

for my $line (<$fh>) {
    chomp;                      # chomp $line  — but $line was aliased to $_
    print if /\bERROR\b/;       # print $_ if $_ =~ /\bERROR\b/
}

The full list of built-ins that default to $_ includes chomp, chop, lc, lcfirst, length, pos, print, printf, quotemeta, say, split (default pattern), study, uc, ucfirst, unlink, the m// and s/// operators, the tr/// operator, and the <>/-X filetest operators. Their detail pages name $_ as the default; this page is the canonical description.

Aliasing inside for and while#

The for (and foreach) loop aliases $_ to each element of the list, in turn:

my @items = (1, 2, 3);
for (@items) {
    $_ *= 2;                     # mutates @items in place
}
# @items is now (2, 4, 6)

Modifying $_ inside the loop modifies the list element itself. This is identical behaviour to map, grep, any, all — and first and reduce from List::Util.

while (<$fh>) does not alias — it reads each line into $_ as a fresh copy. You cannot push back into the file by assigning to $_ in a while (<$fh>) loop.

Localising $_#

A subroutine that wants its own $_ without disturbing the caller’s must local-ise it:

sub categorise {
    local $_ = shift;            # decouple from caller's $_
    return 'small'  if /^\d{1,3}$/;
    return 'medium' if /^\d{4,6}$/;
    return 'large';
}

my @sizes;
for ('5', '12345', '999999999') {
    push @sizes, categorise($_); # caller's $_ stays the loop alias
}

Without the local, calling categorise() with shift would work — but any =~, /.../, or chomp inside it would silently read or write the loop alias, breaking the caller’s iteration.

$_ as an lvalue#

$_ is a real scalar variable; you can assign to it, take a reference to it, and pass it as an lvalue:

$_ = 'hello';
chomp;                           # nothing to chomp; $_ unchanged
s/l/L/g;                          # $_ is now 'heLLo'

my $ref = \$_;                    # \$_ is the alias's address
$$ref = 'goodbye';               # mutates whatever $_ is currently bound to

Beware that the second $$ref will write to whatever $_ is right now — which inside a for loop is the current list element. References to $_ taken outside a loop and used inside one rarely do what the author meant.

Lexical $_#

our $_ and my $_ were experimental features that have been removed. $_ is always the package-global; use local $_ for isolation.

@_ — subroutine arguments#

Inside a subroutine, @_ is the array of arguments passed to that call. Each element is aliased to the caller’s expression — @_ is not a copy:

sub double {
    $_[0] *= 2;                  # mutates the caller's variable
}

my $x = 5;
double($x);
# $x is now 10

This is why most subs start with my (...) = @_; — the unpacking creates copies, after which the routine cannot accidentally mutate caller state:

sub greet {
    my ($name, $greeting) = @_;  # decoupled from caller
    $greeting //= 'Hello';
    return "$greeting, $name!";
}

The aliasing is occasionally useful — it is how chomp(@lines) mutates every element of the caller’s array — but in everyday code the unpacked-copy idiom is the rule.

wantarray and the calling context#

A sub that wants to behave differently depending on whether it was called in scalar, list, or void context inspects wantarray:

sub items {
    return wantarray ? (1, 2, 3) : 3;
}

my @list = items();              # (1, 2, 3)
my $cnt  = items();              # 3
items();                          # void — return value discarded

@_ and wantarray are the two pieces of the calling-convention picture. @_ says what was passed; wantarray says what is expected back.

@_ after shift, pop, unshift, push#

Modifying @_ itself (not its elements) has no aliasing effect on the caller — it’s a normal local array variable. shift @_ removes the first argument, leaving the rest:

sub method_call {
    my $self = shift;            # standard OO pattern
    my %args = @_;               # rest of args as a hash
    ...
}

shift with no arguments inside a subroutine defaults to @_, which is why you see my $self = shift; everywhere.

$_ = shift — wait, what?#

A common deceptive idiom:

sub trim {
    $_ = shift;                  # — set caller's $_ — DO NOT DO THIS
    s/^\s+//;
    s/\s+$//;
    return $_;
}

That $_ = shift writes to the package-global $_, which is the caller’s loop topic if the caller is inside a for. The fix is local-isation, as above:

sub trim {
    local $_ = shift;
    s/^\s+//;
    s/\s+$//;
    return $_;
}

See also#

  • map, grep — the most common consumers of $_ aliasing.

  • shift, pop — default to @_ inside a subroutine.

  • wantarray — the companion of @_ in the calling-convention picture.

  • local — the safe way to set $_ inside a sub that the caller might be iterating with.

  • Regex binding=~ is what you use when you don’t want the implicit $_ target.