in reply to Using hashref values in constant declarations.

G'day nameofmyuser,

Welcome to the Monastery.

Perl provides a number of special blocks which are executed at various points during the lifetime of the program: "BEGIN, UNITCHECK, CHECK, INIT and END". You can use these to check your assumptions about what's happening at these various points.

[Warning: Do read the linked documentation, especially the begincheck example. Some of those blocks are executed in FIFO order; and some in LIFO order. It's not intuitively obvious which is which.]

Your assumptions appear to be correct; although, the phrase "@test array is allocated at compile time" could be misinterpreted. To be clear, in both of these:

my $var1; my $var2 = 'val2';

The variables are declared at compile time; but no assignment occurs at this time. The "$var2 = 'val2'" part of that second statement occurs at runtime.

Here's an example using some of those special blocks. It's just a start: modify and extend as necessary.

#!/usr/bin/env perl -l use strict; use warnings; my $hashref = { a => 1, b => 2 }; my @array = qw{c d e}; use constant { HR_ARRAY => [ sort values %$hashref ], AREF => \@array, }; BEGIN { print join ' ', 'B1:', sort(keys %$hashref), @array } BEGIN { print join ' ', 'B2:', @{+HR_ARRAY}, @{+AREF} } INIT { @array = qw{f g h} } INIT { print join ' ', 'I1:', sort(keys %$hashref), @array } INIT { @array = qw{i j k} } INIT { print join ' ', 'I2:', @{+HR_ARRAY}, @{+AREF} } print join ' ', 'R1:', sort(keys %$hashref), @array; print join ' ', 'R2:', @{+HR_ARRAY}, @{+AREF};

Output:

B1: B2: I1: f g h I2: i j k R1: a b c d e R2: c d e

Using constant for references is generally a bad choice. It makes the token that points to the reference a constant; but, it does not make the values of the reference constants. Consider these:

$ perl -E 'use constant AREF => [1..4]; say "@{+AREF}";' 1 2 3 4 $ perl -E 'use constant AREF => [1..4]; say "@{+AREF}"; AREF = []' Can't modify constant item in scalar assignment at -e line 1, at EOF Execution of -e aborted due to compilation errors. $ perl -E 'use constant AREF => [1..4]; say "@{+AREF}"; AREF->[2] = 99 +; say "@{+AREF}"' 1 2 3 4 1 2 99 4

In terms of workarounds: one of the Anonymous Monks showed a BEGIN block; you could potentionally use an INIT block with a variation of what my code showed for AREF; you could also just use two constants, something like this:

use constant { ONE => 1, ..., FOUR => 4 }; use constant NUM_AREF => [ ONE .. FOUR ];

[Note: I've used NUM_AREF which could probably be improved upon; however, HASHREFCONST is a poor, and highly misleading, choice for an arrayref constant: it will make subsequent code difficult to understand, and runs a high risk of being the source of coding errors.]

If you tell us how this code is intended to be used, we can probably offer more concrete suggestions.

See also: enum — a CPAN module which you might find useful.

— Ken

Replies are listed 'Best First'.
Re^2: Using hashref values in constant declarations.
by AnomalousMonk (Archbishop) on Sep 09, 2017 at 18:46 UTC
    In terms of workarounds ...

    For the benefit of the novice PerlMonk, it should be emphasized that none of the workarounds address (nor, I'm sure, were intended to address) the total mutability of the content of "constant" references:

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "use constant { ONE => 1, FOUR => 4 }; use constant AREF => [ ONE .. FOUR ]; dd AREF; ;; AREF->[3] = 99; dd AREF; ;; AREF->[9] = 999; dd AREF; ;; $#{ +AREF } = -1; dd AREF; " [1, 2, 3, 4] [1, 2, 3, 99] [1, 2, 3, 99, undef, undef, undef, undef, undef, 999] []
    A search of MetaCPAN for "lock" yields a couple of interesting-looking modules, neither of which have I used and so cannot recommend: Data::Lock and Array::Lock.

    In general, Perl handles the important concept of immutability very poorly. I have the vague notion that Perl 6 does better in this respect; can anyone comment?


    Give a man a fish:  <%-{-{-{-<

      A search of MetaCPAN for "lock"

      This reminds me of the core module Hash::Util:

      #!/usr/bin/env perl use warnings; use strict; use Hash::Util qw/lock_hash/; my %x = ( foo => "bar" ); lock_hash %x; eval { $x{y}++; 1 } or warn $@; eval { $x{foo}="quz"; 1 } or warn $@; __END__ Attempt to access disallowed key 'y' in a restricted hash at lock.pl l +ine 9. Modification of a read-only value attempted at lock.pl line 10.

      Although there was some discussion on P5P about removing them a while back, I'm not sure if that will happen.

      For completeness, there are also tied hashes, which could implement the same thing.

Re^2: Using hashref values in constant declarations.
by haukex (Archbishop) on Sep 09, 2017 at 09:02 UTC
    perl -E 'use constant AREF => [1..4]; say "@{+AREF}"; AREF->[2] = 99; say "@{+AREF}"'

    Good post, this bit in particular reminded me of the recent thread constant vector on exactly that topic.