Modules · Language · 0.09
Legba
Named slots every package shares, with watchers, locks and compile-time ops.
Importing a slot name gives a package an accessor, and every package that imports the same name reads and writes the same value. A call with a literal name, for a slot that exists at compile time, is compiled to a custom op, and watchers cost nothing until one is added.
package Config;
use Legba qw(app_name debug);
app_name('shop');
debug(0);
package Checkout;
use Legba qw(app_name debug); # the same two slots, by name
sub banner { app_name() . (debug() ? ' [debug]' : '') }
package main;
Legba::watch('debug', sub { my ($slot, $value) = @_; print "$slot is now $value\n" });
print Checkout::banner(), "\n"; # shop
Config::debug(1); # debug is now 1
print Checkout::banner(), "\n"; # shop [debug]
What you get
-
Shared by name
use Legba qw(app_name)in two packages gives both an accessor to one value. Call it with an argument to set, without to read. -
Compiled to custom ops
With a literal name, for a slot made by
use Legba,Legba::getandsetbecome custom ops andLegba::indexfolds to a constant. A name in a variable goes through XS. -
Watchers, when you want them
Legba::watchcalls back on every set, even to the same value. A slot nobody watches pays nothing for the feature. -
Lock and freeze
_lockrefuses sets until_unlock, and_freezerefuses them for good. Reads always work. -
Threads and forks
After a fork the child has its own copy. Across threads, store a
threads::sharedvalue in the slot: Legba is the name, the shared value the storage. -
For other XS
_slot_ptrhands over the slot's stableSV*, and_make_get_opand_make_set_opbuild ops another module puts in its own optree.
In use
use Legba qw(api_base retries);
api_base('https://api.example.com');
retries(3);
Legba::_freeze('api_base'); # for good
Legba::_lock('retries'); # until unlocked
eval { api_base('http://elsewhere') };
print "frozen: ", ($@ =~ /^(.*?) at /)[0], "\n";
eval { retries(10) };
print "locked: ", ($@ =~ /^(.*?) at /)[0], "\n";
Legba::_unlock('retries');
retries(5);
print api_base(), ' tries ', retries(), " times\n";
print join(', ', sort grep { /^(?:api_base|retries)$/ } Legba::slots()), "\n";
Measured in its POD
As the POD records it, on a threaded perl on Apple Silicon: about 55 million reads a second and 142 million writes, through the accessor or a Legba::get or set with a literal name, which compile to the same op.