NAME
Context::Vars - variables with context scope
VERSION
Version 0.02
SYNOPSIS
use Context::Vars q{$variable};
$variable = 'one';
sub change {
$variable = 'two';
print $variable; # two
}
change();
print $variable; # one
# A callback run later sees the values of the moment it was wrapped.
sub handle {
my ($id) = @_;
$variable = $id;
return Context::Vars->wrap(sub { print "$variable\n" });
}
my $later = handle('request 42');
$later->(); # request 42
DESCRIPTION
A name given to use becomes a scalar in the calling package. Every package that imports the same name shares the one variable, and what it reads is the value in the context that is current at that moment.
An assignment to the variable holds until the sub it is written in returns, through any block in that sub and any way out of it, and is seen by every sub that sub calls. Code outside any sub keeps what it assigns for the program.
A callback wrapped with "wrap", or run with "run" in Context::Vars::Context, sees the values of the moment it was wrapped or captured, wherever and whenever it runs: from an event loop, after other work has changed them, or after other requests have come and gone.
ARRAYS, HASHES AND STRUCTURES
use Context::Vars qw(@trail %seen $config);
Arrays and hashes are imported as scalars are, and follow the same rule: a change to one, an element stored or deleted, a push, a whole assignment, holds until the sub it is written in returns.
The rule goes all the way down. A plain hash or array stored in any context variable, at any depth, belongs to the context: $seen{a}{b} = 1, push @{ $seen{list} }, 1 or $config->{db}{host} = 'x' in a sub is undone when that sub returns, and a capture or a wrapped callback sees the structure as it was at that moment. What is stored is the variable's own copy: changing the hash or array that was assigned does not change the variable, and the other way round.
An object, or a code reference, stored anywhere in such a structure is kept as the reference it is, and what it points at is shared, as its class expects.
What you read back is not the hash or array that was stored but one that stands for it: ref says HASH or ARRAY and everything a hash or array does works, but two reads of $seen{a} are two different references, and == between them is false. Copy one out, { %{ $seen{a} } }, for an ordinary hash.
Reading or writing an element costs more than it does in an ordinary hash or array: some hundreds of nanoseconds against some tens, and more for each level down.
LIMITS
Names are plain identifiers:
$name,@name,%name.No event loop captures for you. A callback sees its registering code's values only when it is wrapped; see "CALLBACKS AND LOOPS".
An assignment the module cannot see when the sub is compiled is not scoped to that sub. That is one made through
@_, afor,grepormapalias, a symbolic reference, a stringevalinside a sub that makes no other assignment, or a hash or array read out of a variable and kept in a lexical before it is written through:my $h = $seen{a}; $h->{b} = 1. It changes whatever context is current.A sub that only assigns a variable for its caller changes nothing the caller can see: the assignment ends when that sub returns. Return the value and let the caller assign it.
CALLBACKS AND LOOPS
A callback that runs later, from an event loop, a queue or a future, sees the values of the moment it was registered only if whatever registered it captured them. "wrap" does that for one callback. A loop that does it for every callback it keeps is said to be wired.
A callback on a loop that is not wired runs outside any context. There a variable reads nothing, unless code outside any sub has assigned it, in which case it reads that value: never the value of the task that registered the callback.
ASYNC SUBS
Under Future::AsyncAwait, an async sub keeps its own variables across await: after the await it reads what it could see before it, and what it assigns is not seen by the code that resumed it. This needs nothing from Future::AsyncAwait to install, and works whichever of the two modules is loaded first.
METHODS
These are for code that runs other code later: an event loop, a queue, a future, a test. An application that only reads and assigns its variables does not need them.
capture
my $ctx = Context::Vars->capture;
Returns a Context::Vars::Context holding the values every variable has now. Later assignments, here or anywhere, do not change what it holds.
wrap
my $callback = Context::Vars->wrap(sub { ... });
Returns a code reference that calls the given one with the values every variable has now, wherever and whenever it is called. Its arguments are passed through and its return value is returned. Each call starts from those values afresh: nothing one call does is seen by the next.
current
my $ctx = Context::Vars->current;
Returns a Context::Vars::Context for the context code is running in now, rather than a copy of it. Code run in it with "run" in Context::Vars::Context and the code running now share their values.
C ABI
An event loop, a future or a queue written in C can capture the variables when a callback is registered and run the callback with them, and C code can read and assign a variable by name, with no Perl call in between. The header, context_vars_abi.h, is installed with this module and found through ExtUtils::Depends; it describes the table of functions, how to find it at run time, and the three calls a loop makes for each callback. A consumer needs that header and nothing else.
DEPENDENCIES
HAMT. Loading this module fails, with a message that says why, when HAMT is not installed or is too old.
AUTHOR
LNATION <email@lnation.org>
BUGS
Please report any bugs or feature requests to bug-context-vars at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Context-Vars.
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)