Context#

Almost every operator in Perl evaluates its operands in a specific context — list, scalar, void, or boolean — and many operators return different things depending on the context they were called in. The same expression can mean different things in different positions:

my @arr = (10, 20, 30);

my @copy = @arr;          # list context     — three elements
my $len  = @arr;          # scalar context   — 3
print @arr;               # list context     — "102030"
print "@arr";             # list context inside ""  — "10 20 30"
print "" . @arr;          # scalar context (concat) — "3"
@arr;                     # void context — discarded; warns under -w

Context is the single biggest difference between Perl and most other languages, and the single most common source of «why doesn’t this do what I expect» surprises.

The four contexts#

Context

What the operand sees

Imposed by

list

«give me all of your values»

@a = ..., (...), function args, print

scalar

«give me one value»

$s = ..., if/while, ., +, comparison

void

«throw the result away»

a statement whose value isn’t used

boolean

«give me a true/false»

if, unless, while, &&, `

Boolean context is technically a special case of scalar context — the operand is asked for one value, then that value is tested for truth. The two are not always the same: a wantarray-aware sub can detect boolean context separately (see below).

Imposing context#

The left side of an assignment imposes context on the right:

my @x = func();           # func() is called in LIST context
my $x = func();           # func() is called in SCALAR context
my ($x, $y) = func();     # func() is called in LIST context
my ($x) = func();         # also LIST — note the parens
my  $x  = func();         # SCALAR — same chars, very different

The single most-tripped-over case is my $x = func() vs my ($x) = func(). Without parens, the assignment is a scalar; with them, it’s a 1-element list assignment. If func() returns three things in list context and «the count» in scalar context, the difference is between getting 'first-thing' and getting 3.

Operators impose context too. Numeric and string operators impose scalar context on their operands; print imposes list:

my @arr = (1, 2, 3);
my $n = @arr + 0;         # scalar context — 3 + 0 = 3
my $s = @arr . "";        # scalar context — "3"
print @arr;               # list context — prints "123"

And the boolean tests impose scalar (boolean) context:

if (@arr)        { ... }  # true if @arr is non-empty
unless (%hash)   { ... }  # true if %hash is empty
while (<$fh>)    { ... }  # context is BOOLEAN, but the diamond op is
                          #   special: it reads ONE line and assigns to $_

What an array yields in scalar context#

An array in scalar context yields its length:

my @arr = (1, 2, 3);
my $n = @arr;            # 3

A list literal in scalar context yields its last element (the comma operator):

my $x = (1, 2, 3);       # 3   — comma operator, last element
my $x = ('a', 'b', 'c'); # 'c'

These look identical and behave differently. The rule is: arrays have a length, list literals don’t. A bare comma-list is the C comma operator and produces its last operand; an array variable in scalar position is asking «how many»:

my @a = ('x', 'y', 'z');
my $count   = @a;        # 3
my $last_el = $a[-1];    # 'z'

The scalar operator forces scalar context on whatever follows, which is most useful when the expression position is otherwise ambiguous:

print "got " . scalar(@arr) . " items\n";     # "got 3 items"
print "got " . @arr . " items\n";              # same — concat imposes scalar
print "got @arr items\n";                      # "got 1 2 3 items" — list inside ""

What a hash yields in scalar context#

A non-empty hash in scalar context returns a true value (the count of keys, since Perl 5.25); an empty hash returns the false value 0. The shape that matters is the truth value:

if (%h) { ... }         # true if %h has any pairs
my $n = keys %h;        # explicit: count of keys
my $n = %h;             # also count of keys (Perl 5.25+); was a debug ratio earlier

For older code targeting pre-5.25 perls you sometimes still see scalar keys %h; on PetaPerl (target perl 5.42) scalar %h returns the key count and is fine.

wantarray — write context-sensitive subs#

A sub can ask «what context was I called in?» with wantarray:

sub items {
    return wantarray ? (1, 2, 3)        # list context
         : defined wantarray ? 3        # scalar context
         : do { warn "items() called in void context\n"; () };  # void context
}

my @list = items();       # (1, 2, 3)
my $cnt  = items();       # 3
items();                  # void — warning fires

The three-way distinction is the only way to detect void from inside a sub. Use it sparingly: most subs return one shape and let the caller worry about context coercion. The places where wantarray earns its keep are:

  • Functions that legitimately return either «the list» or «the count» — e.g. text-search routines.

  • Diagnostic helpers that print a warning when their result was discarded.

A sub that returns different meanings (not just different shapes) based on wantarray is a maintenance hazard. Two named functions read better than one polymorphic one.

Pitfall: scalar(@arr) vs @arr in different positions#

my @arr = (1, 2, 3);

# 1. Function arguments — LIST context
some_func(@arr);          # passes 1, 2, 3 as three arguments
some_func(scalar @arr);   # passes 3 as a single argument

# 2. String concatenation — SCALAR context
"got " . @arr             # "got 3"

# 3. Inside double quotes — array interpolation, NOT scalar!
"got @arr"                # "got 1 2 3"

# 4. Boolean test — SCALAR (boolean) context
if (@arr) { ... }         # true iff @arr non-empty

# 5. Comparison — SCALAR context on both sides
@arr == 3                 # 3 == 3 is true
@arr eq "3"               # "3" eq "3" is true; this is rarely what you want

The mismatch between case 2 (concat → scalar) and case 3 (inside "" → list) is the single most-asked Perl context question. Inside "", @arr is array interpolation; outside "", the context of the surrounding expression decides.

Pitfall: list-flattening in function arguments#

A function receives @_ as a single flat list of all its arguments — there is no way for the callee to tell where one array ended and the next began:

sub many {
    print "got ", scalar @_, " args\n";
}

my @a = (1, 2);
my @b = (3, 4, 5);

many(@a, @b);             # 5 args — both arrays flattened
many(\@a, \@b);           # 2 args — two array references
many(scalar @a, scalar @b); # 2 args — two integers (the lengths)

This is the reason references exist: to pass a non-flat shape through the list-flattening calling convention. Anything you want to keep its identity inside @_ must arrive as a reference.

Real example: a sub that returns count or list#

sub digits_of {
    my ($s) = @_;
    return $s =~ /\d/g;     # in list context: all digit chars
                            # in scalar context: TRUE/FALSE (last match)
}

my @digits = digits_of("a1b2c3");      # ('1', '2', '3')   — three matches
my $any    = digits_of("a1b2c3");      # 1                  — boolean

To make digits_of return a count in scalar context, the right-hand side has to coerce explicitly:

sub digits_of {
    my ($s) = @_;
    my @d = $s =~ /\d/g;
    return wantarray ? @d : scalar @d;
}

my @digits = digits_of("a1b2c3");      # ('1', '2', '3')
my $n      = digits_of("a1b2c3");      # 3

This is the canonical «return a list or its length» idiom. Note that without the wantarray switch, return @d would still give the count in scalar context (because of the array-in-scalar rule) — but it’s clearer to be explicit.

See also#

  • Arrays — the array-vs-list-vs-scalar trichotomy expanded.

  • Hashes%h in scalar context.

  • Comma — the operator that builds list literals and yields its last operand in scalar context.

  • wantarray — the in-sub way to ask.

  • scalar — force scalar context.

  • reverse — context-sensitive: a list of scalars in list context, a single reversed string in scalar context.

  • References — passing a non-flat shape through the flattening list-context arg convention.