Faster Readonly variables with Const::XS

So, what exactly is a Readonly variable in Perl? A readonly variable is one that, once assigned a value, cannot be changed. Any attempt to modify it will trigger a runtime error. This mechanism enforces immutability, ensuring that critical values remain untouched and are protected from accidental or unauthorised alterations.

While Perl doesn’t natively support readonly variables in its syntax, this behaviour can be mimicked using various CPAN modules. Two of the most commonly used ones are Readonly, which utilises tie, and Const::Fast, which sets an internal read-only flag on the variable (or SV in XS terms). Both approaches are effective, but I understood after inspecting the code of Const::Fast an XS implementation would likely be faster.

Enter Const::XS — it follows the same strategy as Const::Fast, marking variables with the SvREADONLY flag, but the key difference is that it’s implemented in XS, which does indeed speed up the process.

Here is a basic benchmark of Readonly, Const::Fast, Const::XS and a bonus module Const::PP which I wrote so I could benchmark fully Const::XS with something backwards compatible in perl.

use Benchmark qw(:all);
my $r = timethese(5000000, {
'Readonly' => sub {
Readonly::Scalar my $string => "Hello World";
Readonly::Hash my %hash => (
a => $string,
b => $string,
c => $string
);
Readonly::Array my @array => (
qw/1 2 3/, $string, \%hash
);
die unless $string eq "Hello World";
die unless $hash{a} eq "Hello World";
die unless $array[3] eq "Hello World";
},
'Const::Fast' => sub {
Const::Fast::const my $string => "Hello World";
Const::Fast::const my %hash => (
a => $string,
b => $string,
c => $string
);
Const::Fast::const my @array => (
qw/1 2 3/, $string, \%hash
);
die unless $string eq "Hello World";
die unless $hash{a} eq "Hello World";
die unless $array[3] eq "Hello World";
},
'Const::PP' => sub {
Const::XS::PP::const my $string => "Hello World";
Const::XS::PP::const my %hash => (
a => $string,
b => $string,
c => $string
);
Const::XS::PP::const my @array => (
qw/1 2 3/, $string, \%hash
);
die unless $string eq "Hello World";
die unless $hash{a} eq "Hello World";
die unless $array[3] eq "Hello World";
},
'XS' => sub {
Const::XS::const my $string => "Hello World";
Const::XS::const my %hash => (
a => $string,
b => $string,
c => $string
);
Const::XS::const my @array => (
qw/1 2 3/, $string, \%hash
);
die unless $string eq "Hello World";
die unless $hash{a} eq "Hello World";
die unless $array[3] eq "Hello World";
}
});
cmpthese $r;

...

benchmark

As demonstrated, Const::XS is over 4x more performant than its pure Perl equivalent and nearly 8x faster than Readonly. Therefore, if you're currently using either Readonly or Const::Fast, it might be worth considering a switch to Const::XS for improved performance.

In addition to the const keyword, Const::XS and Const::PP also offers several other functions:

make_readonly

  • Makes a variable read-only.
  • Helps enforce immutability at runtime.

make_readonly_ref

  • Makes a reference read-only.
  • Prevents modification of the referenced data.

unmake_readonly

  • Removes the read-only restriction from a variable.
  • Allows the variable to be modified after this operation.

is_readonly

  • Checks if a variable is read-only.
  • Returns true if the variable cannot be modified.

https://metacpan.org/pod/Const::XS

6 Comments

The link is incorrect: https://metacpan.org/pos/Const::XS

One of the issues with `use const` is that the implementation of using a subroutine makes those consts difficult to use in quoted situations. Does Const::XS have any such limitations? I can't see any from reading the POD.

You should focus the benchmarks only on usage, not on creation. No user who cares about performance is defining constants in a tight loop.

And don't forget about neilb's excellent roundup of constant modules: https://neilb.org/reviews/constants.html

Note that Readonly appears to make use of Readonly::XS if that is available. Readonly::XS does not declare a Perl version dependency that I can see, but it is installed on my Perl 5.8.9.

Leave a comment

About Robert Acock

user-pic I blog about Perl.