$_
is a global variable. Global variables live in symbol tables, and the built-in punctuation variables all live in the symbol table for package main
.
You can see the contents of the symbol table for main
like this:
$ perl -MData::Dumper -e'print Dumper \%main::' # or \%:: for short
$VAR1 = {
'/' => *{'::/'},
',' => *{'::,'},
'"' => *{'::"'},
'_' => *::_,
# and so on
};
All of the above entries are typeglobs, indicated by the *
sigil. A typeglob is like a container with slots for all of the different Perl types (e.g. SCALAR
, ARRAY
, HASH
, CODE
).
A typeglob allows you to use different variables with the same identifier (the name after the sigil):
${ *main::foo{SCALAR} } # long way of writing $main::foo
@{ *main::foo{ARRAY} } # long way of writing @main::foo
%{ *main::foo{HASH} } # long way of writing %main::foo
The values of $_
, @_
, and %_
are all stored in the main
symbol table entry with key _
. When you access %_
, you're actually accessing the HASH
slot in the *main::_
typeglob (*::_
for short).
strict 'vars'
will normally complain if you try to access a global variable without the fully-qualified name, but punctuation variables are exempt:
use strict;
*main::foo = \'bar'; # assign 'bar' to SCALAR slot
print $main::foo; # prints 'bar'
print $foo; # error: Variable "$foo" is not imported
# Global symbol "$foo" requires explicit package name
print %_; # no error