This may have been answered but my search results did not show any relevant information. Reading the documentation for both Readonly and ReadonlyX seems to indicate that using Readonly today will yield acceptable performance. However, running perlcritic (brutal) on a script that contains Readonly yields:
Used module Readonly at line 9, column 3. Readonly.pm is buggy and sl
+ow. Use Const::Fast or ReadonlyX instead, or the core pragma constant
+. (Severity: 2)
Further, as I am tasked with maintaining legacy code and using perlcritic to assure some level of adherence to PBP I find clashes between Readonly and ReadonlyX when these two modules are used by other modules within the same script. Case in point File::BOM which uses Readonly and one my scripts that I have now converted to use ReadonlyX based on the advice of perlcritic (blindly following advice results in stuff like this). So I ask, is it ok to ignore the advice of perlcritic and use Readonly? Is the advice outdated? Readonly does appear to be slower than ReadonlyX:
Readonly:
Benchmark: timing 10000000 iterations of const, literal, normal, ro, r
+o_simple, rotie, tglob...
const: 0 wallclock secs ( 0.37 usr + 0.00 sys = 0.37 CPU) @ 27
+027027.03/s (n=10000000)
(warning: too few iterations for a reliable count)
literal: 0 wallclock secs ( 0.37 usr + 0.00 sys = 0.37 CPU) @ 27
+027027.03/s (n=10000000)
(warning: too few iterations for a reliable count)
normal: 0 wallclock secs ( 0.40 usr + 0.00 sys = 0.40 CPU) @ 25
+000000.00/s (n=10000000)
<b>ro: 1 wallclock secs ( 0.90 usr + 0.00 sys = 0.90 CPU) @
+ 11111111.11/s (n=10000000)</b>
ro_simple: 5 wallclock secs ( 5.71 usr + 0.00 sys = 5.71 CPU) @ 17
+51313.49/s (n=10000000)
rotie: 5 wallclock secs ( 4.68 usr + 0.00 sys = 4.68 CPU) @ 21
+36752.14/s (n=10000000)
tglob: 1 wallclock secs ( 0.66 usr + 0.00 sys = 0.66 CPU) @ 15
+151515.15/s (n=10000000)
ReadonlyX:
Benchmark: timing 10000000 iterations of const, literal, normal, ro, r
+o_simple, rotie, tglob...
const: 0 wallclock secs ( 0.34 usr + 0.00 sys = 0.34 CPU) @ 29
+411764.71/s (n=10000000)
(warning: too few iterations for a reliable count)
literal: 0 wallclock secs ( 0.38 usr + 0.00 sys = 0.38 CPU) @ 26
+315789.47/s (n=10000000)
(warning: too few iterations for a reliable count)
normal: 0 wallclock secs ( 0.49 usr + 0.00 sys = 0.49 CPU) @ 20
+408163.27/s (n=10000000)
<b>ro: 1 wallclock secs ( 0.42 usr + 0.00 sys = 0.42 CPU) @
+ 23809523.81/s (n=10000000)</b>
ro_simple: 2 wallclock secs ( 0.45 usr + 0.00 sys = 0.45 CPU) @ 22
+222222.22/s (n=10000000)
rotie: 1 wallclock secs ( 0.76 usr + 0.00 sys = 0.76 CPU) @ 13
+157894.74/s (n=10000000)
tglob: 0 wallclock secs ( 0.59 usr + 0.00 sys = 0.59 CPU) @ 16
+949152.54/s (n=10000000)
Clearly ReadonlyX is faster than Readonly, however when the verbose form (Readonly::Scalar) is used the difference in timing is really only teased out when the number of iterations is very large...my conclusion(?) is that using Readonly::Scalar is acceptably fast and I should ignore the advice of perlcritic when faced with the issue that is produced when Readonly and ReadonlyX clash.
Consider:
package Boo;
# some module I don't control from CPAN
use strict;
use warnings;
use Readonly;
Readonly::Scalar our $BOO => 'boo';
1;
use strict;
use warnings
use ReadonlyX; # take the advice of perlcritic!
use Boo; # this module uses Readonly
Readonly::Scalar my $FOO => 'bar';
...and then
perl -I . foo.pl
Prototype mismatch: sub Readonly::Scalar ($;$) vs ($$) at /usr/share/p
+erl5/Readonly.pm line 257.
Prototype mismatch: sub Readonly::Scalar ($;$) vs ($$) at /usr/share/p
+erl5/Readonly.pm line 343.
Prototype mismatch: sub Readonly::Readonly (\[%@$]$) vs (\[$@%]@) at (
+eval 7) line 42.Management is only worried about my (our) code...not
+other CPAN modules that use Readonly
Management only cares that my/our code adheres to PBP - we can't control all of the modules the legacy code uses...so this tends to work (sometimes):
use strict;
use warnings;
BEGIN {
use Module::Loaded;
use ReadonlyX;
mark_as_loaded('Readonly');
}
use Boo;
Readonly::Scalar my $FOO => 'bar';
...but not always because ReadonlyX is not a drop in replacement (in all cases) for Readonly
package Boo;
use strict;
use warnings;
use File::BOM;
1;
...and we see this when the use of Readonly is incompatible with ReadonlyX
perl -I . foo.pl
Useless use of reverse in void context at /home/rclauer/lib/perl5/File
+/BOM.pm line 205.
Odd number of elements in hash assignment at /home/rclauer/lib/perl5/F
+ile/BOM.pm line 187.
Compilation failed in require at Boo.pm line 6.
BEGIN failed--compilation aborted at Boo.pm line 6.
Compilation failed in require at foo.pl line 12.
BEGIN failed--compilation aborted at foo.pl line 12.
So perhaps we should
use constant...but PBP suggests that we don't. But more importantly, our/my scripts are not always going to be the ones mixing and matching Readonly and ReadonlyX...and if we happen upon two modules one that use Readonly and one that use ReadonlyX we cross our fingers and hope our Module::Loaded situation works or we need to figure out which module we can adopt, replace or otherwise alter in order to make all of this legacy code work AND adhere to PBP.
I think this is probably enough to get the point across...I'm confused...and seek the wisdom of the monks.