Return values#

A sub returns either by reaching its last statement, by hitting an explicit return, or by being goto-ed somewhere else (see recursion). The returned list is flattened the same way the argument list is — arrays and hashes lose their identity unless you return references — and is then evaluated in the caller’s context.

Implicit return#

If control falls off the end of the body, the value of the last expression statement is returned:

sub square {
    my ($x) = @_;
    $x * $x                      # implicit return
}

say square(5);                   # 25

Implicit return is idiomatic for short, one-expression subs. It is not idiomatic for multi-branch subs, where readers benefit from seeing every exit explicitly marked with return.

If the last statement is a control-flow construct (a for, while, if without an else, …), the returned value is unspecified. The empty sub returns the empty list.

Explicit return#

sub max {
    my ($a, $b) = @_;
    return $a if $a >= $b;
    return $b;
}

Explicit return exits the sub immediately and supplies the return value. Multiple early returns are the standard shape for guarded code:

sub fetch {
    my ($id) = @_;
    return       unless defined $id;     # void/empty
    return undef if      $id eq '';      # explicit undef in scalar
    ...
}

Note the difference between return; and return undef;:

  • return; returns the empty list in list context, undef in scalar context, and nothing in void context. It is the context-correct way to say ”no result“.

  • return undef; returns the list (undef) in list context, which has length 1 — so a caller writing if (my @r = my_sub()) { ... } will see a one-element list and the if will fire. This is almost always wrong.

The rule of thumb: write return; to indicate failure or absence; write return undef; only when the caller is guaranteed to be in scalar context.

List flattening on return#

The same flattening that applies to arguments applies to return values:

sub two_lists {
    my @a = (1, 2);
    my @b = (3, 4);
    return (@a, @b);             # returns (1, 2, 3, 4) — one flat list
}

my ($x, $y) = two_lists();       # $x = 1, $y = 2 ; rest discarded
my @all     = two_lists();       # @all = (1, 2, 3, 4)
my (@p, @q) = two_lists();       # @p = (1, 2, 3, 4), @q = ()

The last line is the classic surprise: @p greedily slurps the whole list because list-assignment to a flat array on the LHS has no way to know where one logical group ends and the next begins. To return two arrays distinctly, return references:

sub two_lists {
    return (\@a, \@b);
}

my ($pref, $qref) = two_lists();

Context-sensitive return#

sub items {
    if (wantarray) {
        return (1, 2, 3);        # list context
    }
    elsif (defined wantarray) {
        return 3;                # scalar context: count
    }
    else {
        return;                  # void: nothing to compute
    }
}

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

The ”void early return“ branch is a real optimisation pattern — expensive computations should not run when the caller throws the result away.

For the full discussion of wantarray and how it composes with :lvalue, see lvalue and context.

Returning hashes and arrays#

Returning a @array or %hash directly works only because of flattening:

sub config {
    return (host => 'localhost', port => 80);
}

my %c = config();                # %c is the hash
my @c = config();                # @c = ('host', 'localhost', 'port', 80)

For larger structures, return references:

sub config {
    my %c = (host => 'localhost', port => 80);
    return \%c;                  # one ref, no flattening
}

my $c = config();
say $c->{host};

References are also the only way to return multiple aggregates without the caller having to know their sizes.

return inside an eval#

return inside a do {} or eval {} block returns from the enclosing sub, not from the block:

sub safe {
    my $result = eval {
        return 'inside';         # this returns from `safe`, not from eval
    };
    return $result;              # never reached
}

To exit just the eval, use a value ('inside' as the last expression of the block) — eval returns the value of its last expression like any other block.

Returning from BEGIN/END#

BEGIN, END, INIT, CHECK, and UNITCHECK blocks are subs in the technical sense but their return value is discarded. Don’t bother writing return ... inside them.

See also#