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#
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.