wantarray#
Report the calling context of the currently executing subroutine.
wantarray lets a subroutine ask the runtime how its caller wrote
the call: was the result assigned to a list, to a scalar, or thrown
away? The answer is one of three distinct values, and a sub can use
it to return different shapes of data, or to skip expensive work
altogether when the caller asked for nothing.
Synopsis#
wantarray
Takes no arguments and has no parentheses form — it is a keyword, not a function call.
What you get back#
wantarray returns one of exactly three values, corresponding to the
three contexts Perl distinguishes:
Return value |
Context of the caller |
Typical caller syntax |
|---|---|---|
true ( |
list |
|
false ( |
scalar |
|
void |
|
The three-way distinction is why the function “should have been named
wantlist()”: the boolean-looking return is actually tri-state, and
defined wantarray is the right test for “did the caller want
anything at all”.
The canonical idiom#
The pattern wantarray exists for is a sub that adapts its return
shape to the caller:
sub records {
my @rows = heavy_query();
return wantarray ? @rows : "@rows";
}
my @r = records(); # gets the list
my $s = records(); # gets a space-joined string
records(); # still runs heavy_query — see below
Pair that with an early-out when the caller asked for nothing:
sub records {
return unless defined wantarray; # caller wrote `records();`
my @rows = heavy_query(); # skipped in void context
return wantarray ? @rows : "@rows";
}
defined wantarray is the void-context guard. wantarray alone is
not — it is false in both scalar and void, and an early return on
a false wantarray would break every scalar-context caller.
Context is propagated, not re-interpreted#
wantarray reports the context the caller imposed on the sub, not
what the sub does internally:
sub ctx { wantarray ? "list" : defined wantarray ? "scalar" : "void" }
my @a = ctx(); # "list"
my $s = ctx(); # "scalar"
ctx(); # "void"
print ctx(), "\n"; # "list" — print's LIST is list context
scalar ctx(); # "scalar" — scalar() forces scalar context
Note the last two: print imposes list context on its arguments, and
scalar explicitly forces scalar context. Neither is about what
ctx does with the result.
Calls from void context#
A sub called as a bare statement runs in void context, and
wantarray returns undef inside that sub. This does not cascade:
a sub called from within a void-context sub sees whatever context
its own caller imposed.
sub inner { defined wantarray ? "wanted" : "void" }
sub outer { my $x = inner(); return $x }
outer(); # outer is void; inner is scalar → "wanted"
Each call site establishes its own context independently. wantarray
always reports the nearest enclosing sub’s context, not the dynamic
chain’s.
Works inside eval too#
wantarray also reports the context of an eval block or
eval EXPR, not just named subroutines:
my @x = eval { wantarray ? (1, 2, 3) : "scalar" }; # (1,2,3)
my $x = eval { wantarray ? (1, 2, 3) : "scalar" }; # "scalar"
eval { defined wantarray ? 1 : 0 }; # void → 0
This is the same mechanism — eval is a call frame in the same
sense a sub is.
Where wantarray has no useful answer#
wantarray’s result is unspecified at these places, and code
should not rely on any particular value:
The top level of a file (outside any sub).
Inside a
BEGIN,UNITCHECK,CHECK,INIT, orENDblock.Inside a
DESTROYmethod.
Treat wantarray as meaningful only within an ordinary sub or
eval. Anywhere else, design your code so the answer does not
matter.
Examples#
A getter that returns the full list to list callers, the count to scalar callers, and does nothing in void context:
sub warnings {
return unless defined wantarray;
my @w = collect_warnings();
return wantarray ? @w : scalar @w;
}
my @all = warnings(); # every warning
my $count = warnings(); # just the number
warnings(); # collect_warnings() is not called
A sub that refuses to be called in void context because the return value is the whole point:
sub must_use {
defined wantarray
or croak "must_use: return value must be used";
return compute();
}
A sub that emits one element per call in scalar context and the whole batch in list context — a shape some iterator-style APIs expose:
sub next_batch {
state @queue;
@queue = refill() unless @queue;
return wantarray ? splice(@queue) : shift @queue;
}
Edge cases#
No parentheses, no arguments.
wantarray()parses but the empty parens are noise; the keyword takes nothing.wantarray $xis a syntax error, not a call with an argument.Not the caller’s context for operators.
wantarrayreports the call-frame context only. An expression like$sub->() + 1puts the call in scalar context;wantarrayinside$subsees scalar, as expected. There is no way to ask “was I called inside an arithmetic expression” — only list / scalar / void.returnhonours the same context.return @listin scalar context yields the last element, not the count — becausereturnitself sees the caller’s context. Usereturn wantarray ? @list : scalar @listwhen you want the count for scalar callers.Boolean context is scalar context.
if (f())callsfin scalar context;wantarrayreturns false there, notundef.List assignment to an empty list is still list context.
() = f();is list context even though the result is discarded.wantarrayreturns true. This is useful for forcing list context on a sub whose side effects depend on it.wantarrayis not available in XS callers the same way. An XSUB inspects context throughGIMME_V; a Perl sub called from an XSUB sees the context the XSUB established for the call.Prototypes do not change
wantarray. A($)prototype forces an argument’s context, not the sub’s own call context.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
return— honours the same list/scalar/void contextwantarrayreports; the two are designed to be used togethercaller— inspect the call stack itself (package, file, line, and, in its three-arg form, more context details including whetherwantarraywould return true there)scalar— force scalar context on an expression, which is what makeswantarrayreturn false in the calleeeval— establishes a call frame whose contextwantarrayalso reports