# Lvalue subs and context Two related topics that come up wherever a sub needs to behave differently depending on how it is being used: **`:lvalue`** subs (those usable on the left-hand side of an assignment) and **`wantarray`**-driven dispatch on the caller’s context. ## Why context matters in subs Every Perl expression evaluates in a context — list, scalar (with sub-flavours: numeric, string, boolean), or void — that’s imposed by what surrounds it. A sub call inherits the context of its position: ```perl my @r = my_sub(); # list context my $r = my_sub(); # scalar context my_sub(); # void context print my_sub(); # list context (print's args are LIST) my $n = () = my_sub(); # scalar of (a list assignment) — element count ``` For most subs, this is invisible — they return the same data either way and Perl’s automatic context conversion does the right thing. For some subs the work is genuinely different depending on context, and those subs benefit from explicitly inspecting [`wantarray`](../perlfunc/wantarray.md). ## `wantarray`: the three-way switch ```perl sub items { if (wantarray) { return (1, 2, 3); # list context } elsif (defined wantarray) { return 3; # scalar context } else { return; # void context — caller will # discard whatever we return } } ``` The three return values of `wantarray`: | Return value | Caller’s context | Practical meaning | |----------------|--------------------|----------------------------------------| | `1` (true) | list | return all the things | | `0` (false) | scalar | return one thing (e.g. count) | | `undef` | void | nobody cares; consider returning early | `defined wantarray` is the test for «scalar or list» (anything non-void). ### The void-context shortcut When work is expensive and the caller threw the result away, return early: ```perl sub expensive_query { return unless defined wantarray; # nothing to compute my @rows = $db->select(...); # actually do the work return wantarray ? @rows : scalar @rows; } expensive_query(); # void: returns immediately my @r = expensive_query(); # list: full result my $n = expensive_query(); # scalar: count ``` This pattern is the single best reason to consult `wantarray`: turning a «always do the work» sub into a «do the work only if the caller wants it» sub. ### When *not* to use `wantarray` - For convenience overloading. A sub that returns a hashref in scalar context and a hash in list context is a maintenance hazard — readers can’t tell from the call site which they’re getting. Pick one. - For subs that are obviously list-y or scalar-y. A sub named `count_users` should return a number; readers do not expect it to behave differently in list context. ## `:lvalue` subs An `:lvalue` sub is one whose return value is itself assignable. The body must end in an expression that has a memory location — typically a `my` lexical or an aggregate element: ```perl sub editable :lvalue { my $self = shift; $self->{counter}; # last expression is an lvalue } my $obj = { counter => 0 }; bless $obj, 'Counter'; $obj->editable = 42; # writes through to $obj->{counter} ``` The body’s last expression is what the assignment writes to. If that expression is not an lvalue (`return $x + 1`, `return scalar @list`), the assignment is illegal and you’ll get a clear error. `:lvalue` is rarely the right tool. The only places it pays for itself: - Tied variables and tied-like wrappers, where the sub is mediating access to a real lvalue underneath. - DSLs that genuinely want assignment-syntax for setting (eg. `$config->host = 'localhost';`). For «set a property on an object», a plain setter is clearer: ```perl sub set_counter { my ($self, $value) = @_; $self->{counter} = $value; return $self; # method chaining } $obj->set_counter(42); # explicit, no surprises ``` ## `:lvalue` and the body’s structure Because the body’s last expression is special, the rules are restrictive: ```perl sub good :lvalue { $self->{x} } # OK — last expr is lvalue sub also_good :lvalue { my @scratch = ...; # work $self->{x}; # last expr is lvalue } sub bad :lvalue { return $self->{x}; # NOT OK — explicit return # disables :lvalue } sub also_bad :lvalue { if ($cond) { $self->{x} } else { $self->{y} } # an `if` block is not an lvalue } ``` The «no explicit `return`» rule is the same one that makes constant-fold prototypes work; both rely on the body being a single value-producing expression at the end. For the modern alternative — a setter that returns `$self` for chaining — see the [Object-Oriented Programming guide](../../../guide/oop/index.md). ## Combining `:lvalue` with context An `:lvalue` sub cannot easily branch on `wantarray`, because the lvalue version of the call doesn’t quite fit the «returns a value» model. If you want both behaviours from one sub, accept that you are in DSL territory and document the contract carefully — or split into two subs. ## Context-affecting operators A few operators force a specific context on their argument; the sub will see that context regardless of where the surrounding expression is going: ```perl my @r = scalar my_sub(); # scalar() forces scalar context on my_sub my $n = () = my_sub(); # the inner () = ... is list context; # outer assignment to $n is scalar of that ``` The `() = LIST` idiom is the standard way to force list context on a sub call and then read the count. See [assignment](../perlop/assignment.md) for the operator-level discussion. ## See also - [`wantarray`](../perlfunc/wantarray.md) — the keyword. - [Return values](return.md) — the rest of the return-value picture (without the lvalue twist). - [Attributes](attributes.md) — `:lvalue` is one of several built-in attributes. - [Assignment operator](../perlop/assignment.md) — what the caller’s `=` actually does on either side of an `:lvalue` call. - [`scalar`](../perlfunc/scalar.md) — explicit context coercion.