Modules · Data · 0.05

Context::Vars

Variables that follow the work, scoped to a context.

An imported name becomes a variable every package shares, and what it reads is the value in the current context. An assignment holds until the sub it is written in returns, and a callback wrapped now sees these values whenever it runs: from an event loop, or after other requests have come and gone.

use Context::Vars q{$request_id};

$request_id = 'none';

sub handle {
    my ($id) = @_;
    $request_id = $id;        # holds until handle returns
    log_line('started');
}

sub log_line { print "[$request_id] $_[0]\n" }

handle('req-42');             # [req-42] started
log_line('idle');             # [none] idle

What you get

  • Scoped by the sub

    An assignment holds until the sub it is written in returns, through any block and any way out, and every sub it calls sees it. Code outside any sub keeps what it assigns.

  • Shared by name

    Every package that imports the same name shares the one variable, so a request id or a user set in one module is read in another without passing it.

  • Callbacks keep their moment

    Context::Vars->wrap gives a callback the values of the moment it was wrapped, wherever and whenever it later runs.

  • Async subs

    Under Future::AsyncAwait, an async sub keeps its own values across await, whichever of the two modules is loaded first.

  • Arrays, hashes and deeper

    Arrays and hashes follow the same rule all the way down. Reading an element costs some hundreds of nanoseconds against some tens for a plain hash, and the POD says so.

In use

use Context::Vars q{$user};

# a callback run later sees the values of the moment it was wrapped
sub handler_for {
    my ($who) = @_;
    $user = $who;
    return Context::Vars->wrap(sub { print "hello, $user\n" });
}

my @later = map { handler_for($_) } qw(ada grace);
$_->() for @later;            # hello, ada / hello, grace

For C

context_vars_abi.h: an event loop, a future or a queue written in C captures the variables when a callback is registered and runs the callback with them, and C code reads and assigns a variable by name, with no Perl call in between.

Get it

cpanm Context::Vars