• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

eg/H03-May-2022-7770

lib/H03-May-2022-458109

t/H03-May-2022-640458

Build.PLH A D18-Jul-2016301 134

ChangesH A D18-Jul-2016657 2615

LICENSEH A D18-Jul-201618 KiB378292

MANIFESTH A D18-Jul-2016378 2424

META.jsonH A D18-Jul-20162 KiB8281

META.ymlH A D18-Jul-20161.1 KiB4544

README.mdH A D18-Jul-201612.1 KiB330232

cpanfileH A D18-Jul-201657 32

minil.tomlH A D18-Jul-2016184 118

README.md

1[![Build Status](https://travis-ci.org/sanko/readonly.svg?branch=master)](https://travis-ci.org/sanko/readonly)
2# NAME
3
4ReadonlyX - Faster facility for creating read-only scalars, arrays, hashes
5
6# Synopsis
7
8    use strict;
9    use warnings;
10    use ReadonlyX;
11
12    # Read-only scalar
13    my $sca1;
14    Readonly::Scalar $sca1    => 3.14;
15    Readonly::Scalar my $sca2 => time;
16    Readonly::Scalar my $sca3 => 'Welcome';
17    my $sca4 = time();
18    Readonly::Scalar $sca4; # Value is not clobbered
19
20    # Read-only array
21    my @arr1;
22    Readonly::Array @arr1 => [1 .. 4];
23
24    # or:
25    Readonly::Array my @arr2 => (1, 3, 5, 7, 9);
26
27    # Read-only hash
28    my %hash1;
29    Readonly::Hash %hash1    => (key => 'value', key2 => 'value');
30    Readonly::Hash my %hash2 => (key => 'value', key2 => 'value');
31
32    # or:
33    Readonly::Hash my %hash3 => {key => 'value', key2 => 'value'};
34
35    # You can use the read-only variables like any regular variables:
36    print $sca1;
37    my $something = $sca1 + $arr1[2];
38    warn 'Blah!' if $hash1{key2};
39
40    # But if you try to modify a value, your program will die:
41    $sca2 = 7;           # "Modification of a read-only value attempted"
42    push @arr1, 'seven'; # "Modification of a read-only value attempted"
43    $arr1[1] = 'nine';   # "Modification of a read-only value attempted"
44    delete $hash1{key};  # Attempt to delete readonly key 'key' from a restricted hash
45
46    # Create mutable clones
47    Readonly::Scalar $scalar => {qw[this that]};
48    # $scalar->{'eh'} = 'foo'; # Modification of a read-only value attempted
49    my $scalar_clone = Readonly::Clone $scalar;
50    $scalar_clone->{'eh'} = 'foo';
51    # $scalar_clone is now {this => 'that', eh => 'foo'};
52
53# Description
54
55This is a near-drop-in replacement for [Readonly](https://metacpan.org/pod/Readonly), the popular facility for
56creating non-modifiable variables. This is useful for configuration files,
57headers, etc. It can also be useful as a development and debugging tool for
58catching updates to variables that should not be changed.
59
60If you really need to have immutable variables in new code, use this instead
61of Readonly. You'll thank me later. See the section entitled
62["ReadonlyX vs. Readonly"](#readonlyx-vs-readonly) for more.
63
64# Functions
65
66All of these functions can be imported into your package by name.
67
68## Readonly::Scalar
69
70    Readonly::Scalar $pi      => 3.14;
71    Readonly::Scalar my $aref => [qw[this that]]; # list ref
72    Readonly::Scalar my $href => {qw[this that]}; # hash ref
73
74Creates a non-modifiable scalar and assigns a value of to it. Thereafter, its
75value may not be changed. Any attempt to modify the value will cause your
76program to die.
77
78If the given value is a reference to a scalar, array, or hash, then this
79function will mark the scalar, array, or hash it points to as being readonly
80as well, and it will recursively traverse the structure, marking the whole
81thing as readonly.
82
83If the variable is already readonly, the program will die with an error about
84reassigning readonly variables.
85
86## Readonly::Array
87
88    Readonly::Array @arr1    => [1 .. 4];
89    Readonly::Array my @arr2 => (1, 3, 5, 7, 9);
90
91Creates a non-modifiable array and assigns the specified list of values to it.
92Thereafter, none of its values may be changed; the array may not be lengthened
93or shortened. Any attempt to do so will cause your program to die.
94
95If any of the values passed is a reference to a scalar, array, or hash, then
96this function will mark the scalar, array, or hash it points to as being
97Readonly as well, and it will recursively traverse the structure, marking the
98whole thing as Readonly.
99
100If the variable is already readonly, the program will die with an error about
101reassigning readonly variables.
102
103## Readonly::Hash
104
105    Readonly::Hash %h => (key => 'value', key2 => 'value');
106    Readonly::Hash %h => {key => 'value', key2 => 'value'};
107
108Creates a non-modifiable hash and assigns the specified keys and values to it.
109Thereafter, its keys or values may not be changed. Any attempt to do so will
110cause your program to die.
111
112A list of keys and values may be specified (with parentheses in the synopsis
113above), or a hash reference may be specified (curly braces in the synopsis
114above). If a list is specified, it must have an even number of elements, or
115the function will die.
116
117If any of the values is a reference to a scalar, array, or hash, then this
118function will mark the scalar, array, or hash it points to as being Readonly
119as well, and it will recursively traverse the structure, marking the whole
120thing as Readonly.
121
122If the variable is already readonly, the program will die with an error about
123reassigning readonly variables.
124
125## Readonly::Clone
126
127    my $scalar_clone = Readonly::Clone $scalar;
128
129When cloning using [Storable](https://metacpan.org/pod/Storable) or [Clone](https://metacpan.org/pod/Clone) you will notice that the value
130stays readonly, which is correct. If you want to clone the value without
131copying the readonly flag, use this.
132
133    Readonly::Scalar my $scalar => {qw[this that]};
134    # $scalar->{'eh'} = 'foo'; # Modification of a read-only value attempted
135    my $scalar_clone = Readonly::Clone $scalar;
136    $scalar_clone->{'eh'} = 'foo';
137    # $scalar_clone is now {this => 'that', eh => 'foo'};
138
139In this example, the new variable (`$scalar_clone`) is a mutable clone of the
140original `$scalar`. You can change it like any other variable.
141
142# Examples
143
144Here are a few very simple examples again to get you started:
145
146## Scalars
147
148A plain old read-only value:
149
150    Readonly::Scalar $a => "A string value";
151
152The value need not be a compile-time constant:
153
154    Readonly::Scalar $a => $computed_value;
155
156Need an undef constant? Okay:
157
158    Readonly::Scalar $a;
159
160## Arrays/Lists
161
162A read-only array:
163
164    Readonly::Array @a => (1, 2, 3, 4);
165
166The parentheses are optional:
167
168    Readonly::Array @a => 1, 2, 3, 4;
169
170You can use Perl's built-in array quoting syntax:
171
172    Readonly::Array @a => qw[1 2 3 4];
173
174You can initialize a read-only array from a variable one:
175
176    Readonly::Array @a => @computed_values;
177
178A read-only array can be empty, too:
179
180    Readonly::Array @a => ();
181    # or
182    Readonly::Array @a;
183
184## Hashes
185
186Typical usage:
187
188    Readonly::Hash %a => (key1 => 'value1', key2 => 'value2');
189    # or
190    Readonly::Hash %a => {key1 => 'value1', key2 => 'value2'};
191
192A read-only hash can be initialized from a variable one:
193
194    Readonly::Hash %a => %computed_values;
195
196A read-only hash can be empty:
197
198    Readonly::Hash %a => ();
199    # or
200    Readonly::Hash %a;
201
202If you pass an odd number of values, the program will die:
203
204    Readonly::Hash my %a => (key1 => 'value1', "value2");
205    # This dies with "Odd number of elements in hash assignment"
206
207# ReadonlyX vs. Readonly
208
209The original Readonly module was written nearly twenty years ago when the
210built-in capability to lock variables didn't exist in perl's core. The
211original author came up with the amazingly brilliant idea to use the new (at
212the time) `tie(...)` construct. It worked amazingly well! But it wasn't long
213before the speed penalty of tied varibles became embarrassingly obvious. Check
214any review of Readonly written before 2013; the main complaint was how slow it
215was and the benchmarks proved it.
216
217In an equally brilliant move to work around tie, Readonly::XS was released for
218perl 5.8.9 and above. This bypassed `tie(...)` for basic scalars which made a
219huge difference.
220
221During all this, two very distinct APIs were also designed and supported by
222Readonly. One for (then) modern perl and one written for perl 5.6. To make
223this happen, time consuming eval operations were required and the codebase
224grew so complex that fixing bugs was nearly impossible. Readonly was three
225different modules all with different sets of quirks and bugs to fix depending
226on what version of perl and what other modules you had installed. It was a
227mess.
228
229So, after the original author abandoned both Readonly and Readonly::XS, as
230bugs were found, they went unfixed. The combination of speed and lack of
231development spawned several similar modules which usually did a better job but
232none were a total drop-in replacement.
233
234Until now.
235
236ReadonlyX is the best of recent versions of Readonly without the old API and
237without the speed penalty of `tie(...)`. It's what I'd like to do with
238Readonly if resolving bugs in it wouldn't break 16 years of code out there in
239Darkpan.
240
241In short, unlike Readonly, ReadonlyX...
242
243- ...does not use slow `tie(...)` magic or eval. There shouldn't be a
244        speed penalty after making the structure immutable. See the
245        [Benchmarks](https://metacpan.org/pod/Benchmarks) section below
246- ...does not strive to work on perl versions I can't even find a working
247        build of to test against
248- ...has a single, clean API! What do all of these different forms of the
249        original Readonly API do?
250
251        use Readonly;
252        Readonly  my @array1        => [2];
253        Readonly \my @array2        => [2];
254        Readonly::Array  my @array3 => [2];
255        Readonly::Array1 my @array4 => [2];
256
257    Be careful because they all behave very differently. Even your version of perl
258    and the contents of the list changes how they work. Give up? Yeah, me too.
259    Bonus: Guess which one doesn't actually make the list items read only.
260
261- ...does the right thing when it comes to deep vs. shallow structures
262- ...allows implicit undef values for scalars (Readonly inconsistantly
263        allows this for hashes and arrays but not scalars)
264- ...a lot more I can't think of right now but will add when they come to
265        me
266- ...is around 100 lines instead of 460ish so maintaining it will be a
267        breeze
268- ...doesn't clobber predefined variables when making them readonly
269
270    Using Readonly, this:
271
272        my @array = qw[very important stuff];
273        Readonly::Array @array;
274        print "@array";
275
276    ...wouldn't print anything. I consider it a bug but I'm not sure why it was
277    designed this way originally. With ReadonlyX, you won't lose your
278    `'very important stuff'`.
279
280    Note that this is an incompatible change! If you attempt to do this and then
281    switch to plain 'ol Readonly, your code will not work.
282
283# Benchmarks
284
285Don't believe Readonly is slow? Here's the result of basic benchmarking:
286
287    Hash Benchmark: timing 5000000 iterations of const, normal, readonly, readonlyx...
288         const:  3 wallclock secs ( 2.73 usr +  0.02 sys =  2.75 CPU) @ 1818181.82/s (n=5000000)
289        normal:  3 wallclock secs ( 3.02 usr + -0.02 sys =  3.00 CPU) @ 1666666.67/s (n=5000000)
290      readonly: 47 wallclock secs (40.64 usr +  0.03 sys = 40.67 CPU) @ 122931.67/s (n=5000000)
291     readonlyx:  4 wallclock secs ( 3.22 usr + -0.01 sys =  3.20 CPU) @ 1560549.31/s (n=5000000)
292    Array Benchmark: timing 5000000 iterations of const, normal, readonly, readonlyx...
293         const:  3 wallclock secs ( 2.19 usr +  0.03 sys =  2.22 CPU) @ 2253267.24/s (n=5000000)
294        normal:  1 wallclock secs ( 1.44 usr +  0.00 sys =  1.44 CPU) @ 3474635.16/s (n=5000000)
295      readonly: 36 wallclock secs (32.52 usr +  0.13 sys = 32.64 CPU) @ 153181.58/s (n=5000000)
296     readonlyx:  1 wallclock secs ( 1.12 usr + -0.02 sys =  1.11 CPU) @ 4512635.38/s (n=5000000)
297    Scalar Benchmark: timing 5000000 iterations of const, normal, readonly, readonlyx...
298         const:  1 wallclock secs ( 1.14 usr + -0.02 sys =  1.12 CPU) @ 4448398.58/s (n=5000000)
299        normal:  1 wallclock secs ( 0.99 usr +  0.02 sys =  1.00 CPU) @ 4995005.00/s (n=5000000)
300      readonly:  1 wallclock secs ( 1.25 usr +  0.00 sys =  1.25 CPU) @ 4000000.00/s (n=5000000)
301     readonlyx:  2 wallclock secs ( 1.20 usr +  0.00 sys =  1.20 CPU) @ 4156275.98/s (n=5000000)
302
303Find the script to run them yourself in `eg/benchmark.pl`.
304
305# Requirements
306
307There are no non-core requirements.
308
309# Bug Reports
310
311If email is better for you, [my address is mentioned below](#author) but I
312would rather have bugs sent through the issue tracker found at
313http://github.com/sanko/readonly/issues.
314
315ReadonlyX can be found is the branch of Readonly found here:
316https://github.com/sanko/readonly/tree/ReadonlyX
317
318# Author
319
320Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/
321
322CPAN ID: SANKO
323
324# License and Legal
325
326Copyright (C) 2016 by Sanko Robinson <sanko@cpan.org>
327
328This module is free software; you can redistribute it and/or modify it under
329the same terms as Perl itself.
330