Typeglobs#

A typeglob is a single name that holds every variable type with that name in a package — the scalar $foo, the array @foo, the hash %foo, the sub &foo, the filehandle foo, and the format foo all share one symbol-table entry, and *foo is the way to talk about that entry as a value. The sigil is *, deliberately chosen because the asterisk reads as “all”.

*foo                # the typeglob — all of $foo, @foo, %foo, &foo, etc.
*foo{SCALAR}        # ref to $foo
*foo{ARRAY}         # ref to @foo
*foo{HASH}          # ref to %foo
*foo{CODE}          # ref to &foo
*foo{IO}            # the filehandle, if foo is one
*foo{NAME}          # the name "foo" — a string
*foo{PACKAGE}       # the package name — a string

In modern Perl, typeglobs come up rarely. References cover most of what they used to be needed for. The remaining legitimate uses are package aliasing, filehandle creation in older idioms, and a few introspection hooks.

What a typeglob does#

The single most useful sentence about typeglobs:

Assigning to a typeglob makes one name mean another name.

*foo = *bar;        # $foo, @foo, %foo, &foo, FH foo all alias $bar, @bar, %bar, &bar, FH bar

After that assignment, modifying $foo modifies $bar, calling foo() calls bar(), and so on for every type. The two names are now genuinely the same storage — not a copy.

Assigning a reference to a typeglob aliases only that one type:

our @items;
*shortcut = \@items;     # only @shortcut aliases @items; $shortcut and %shortcut unchanged

This is how the Exporter module installs imported subs into the caller’s package: *caller_package::name = \&exporter_package::name. Each imported function gets one slot of one glob assigned, so the rest of the destination package’s variables under that name are untouched.

*name = \&sub — the standard import idiom#

package My::Util;
sub greet { "Hello, $_[0]!" }

package main;
*greet = \&My::Util::greet;       # import greet into main::
print greet("world");              # "Hello, world!"

This is the mechanism that use invokes via Exporter::import — the importing package gets a glob assignment for each requested name. Exporter does it; you can do it by hand for cases Exporter doesn’t fit.

Local glob aliases#

local *name = \$thing is a temporary alias that auto-restores when the enclosing scope exits:

our $config = "default";

sub run_with_config {
    my ($alt_config, $code) = @_;
    local *config = \$alt_config;        # only inside this sub
    $code->();                            # any read of $config reads $alt_config
}

run_with_config("test", sub {
    print "config is $config\n";          # "config is test"
});

print "config is $config\n";              # "config is default" — restored

This is a heavyweight mechanism that has largely been replaced by plain local $config = $alt_config; for scalars and explicit parameter-passing for everything else. The case where it still matters is when you need to alias a filehandle across the call of arbitrary user code (see below).

Filehandle typeglobs#

Before Perl 5.6’s “open my $fh” idiom, filehandles had to be named by package globals or passed as typeglobs:

# Old style — bareword filehandle in a glob slot
open FH, '<', $path or die $!;
while (<FH>) { ... }
close FH;

# Pass to a sub:
sub print_to { my $fh = shift; print $fh "stuff\n" }
print_to(\*FH);                            # ref-to-glob

# Modern style:
open my $fh, '<', $path or die $!;
while (<$fh>) { ... }
close $fh;
print_to($fh);                             # plain scalar ref to IO

The modern style is preferred everywhere new code is written. The typeglob-filehandle form survives in three places:

  1. The standard handlesSTDIN, STDOUT, STDERR are bareword filehandles backed by the typeglobs *STDIN, *STDOUT, *STDERR. You see these in error messages and reset code:

    print STDERR "error\n";
    *STDOUT = *STDERR;          # redirect all STDOUT to STDERR for the rest of the program
    
  2. Returning newly-created filehandles — before lexical filehandles, the way to return a fresh handle from a sub was to local *FH and return *FH:

    sub new_handle {
        my $path = shift;
        local *FH;
        open FH, $path or return;
        return *FH;             # the glob outlives the local because it was returned
    }
    

    Modern equivalent:

    sub new_handle {
        my $path = shift;
        open my $fh, $path or return;
        return $fh;
    }
    
  3. Selecting a different default output handleselect returns and accepts a filehandle, in glob-or-string form:

    my $old = select(STDERR);    # subsequent print without explicit fh writes to STDERR
    print "errors-only output\n";
    select($old);                  # restore
    

*foo{THING} — the slot accessors#

*foo{THING} returns a reference to one slot of the glob, or undef if that slot is empty:

*foo{SCALAR}        # \$foo  if $foo has been touched
*foo{ARRAY}         # \@foo  if @foo has been touched
*foo{HASH}          # \%foo  if %foo has been touched
*foo{CODE}          # \&foo  if &foo defined
*foo{IO}            # the IO handle, or undef

The *foo{IO} form is the one place you regularly see THING syntax in modern code. It’s how you ask “is this scalar holding a filehandle”:

sub is_handle {
    my $thing = shift;
    return defined ref($thing) && (
           ref($thing) eq 'GLOB'
        || (ref(\$thing) eq 'GLOB' && defined *$thing{IO})
    );
}

The standard introspection helper that wraps this is Scalar::Util::openhandle.

*foo{SCALAR} has a quirk: it always returns something — the package’s $foo slot is created on demand. The other accessors return undef when the slot is empty.

What replaces typeglobs#

For the patterns where typeglobs used to be the only answer, the modern alternatives are:

Old typeglob pattern

Modern replacement

Pass a filehandle to a sub

Lexical FH: open my $fh, ...

Return a filehandle from a sub

Lexical FH: return $fh;

Alias @there as @here

our @here; *here = \@there; (still typeglob, no replacement)

Pass an array by reference

\@arr — pass the reference

Install an imported sub

*name = \&Source::name (still typeglob) — or use Exporter

Localised global alias

local $var = ... for plain scalars

The *here = \@there package-aliasing pattern is the one that typeglobs still own outright — there’s no “alias one package variable to another” mechanism that doesn’t go through a glob. Inside Exporter-using modules that mostly happens automatically.

See also#

  • References — the modern alternative to globs for most “indirect access” patterns.

  • Scalars — the dynamic-typing story. Globs are a separate type: ref \*FH returns 'GLOB'.

  • local — the safe way to install a temporary glob alias.

  • select — the selected-output-handle function that takes glob or string handle names.

  • Scalar::Utilopenhandle, reftype, blessed for runtime introspection.

  • Symbol — generate fresh anonymous globs and qualify package names. (No local reference page yet.)