Blog post: Perl's Constant Pragma and Readonly Module
Tags: perl, review, constants
Published: 2019-02-05 08:28:11

---
title: Blog post: Perl's Constant Pragma and Readonly Module
published: true
description: Comparison of Perl's constant pragma and the module Readonly
tags: perl, review, constants
---
The other day I was doing a code review of of some Perl code and I fell over a _magic number_. I pointed it out to the author, emphasizing the concept of using a [constant pragma](https://perldoc.perl.org/constant.html) instead of a regular mutable variable as recommended by the [Perl::Critic](https://metacpan.org/pod/Perl::Critic) policy: [Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers](https://metacpan.org/pod/Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers)

He changed the code accordingly to use a constant, but copied the value of the constant into a regular variable so it could be used in string interpolation, stating that the use of constants in interpolated strings is _ugly_.

I completely agree, but the proposed solution did not make much sense either.

This is an example, so you can visualize the code (_this is not the actual code_):

```perl
use v5.10;

use constant TRUTH => 42;

my $truth = TRUTH;

say "The truth is $truth";
```

A nice constant and proper string interpolation using a regular variable. And the alternative demonstrating the use of the constant in conjunction with the string output:

```perl
use v5.10;

use constant TRUTH => 42;

say 'The truth is '.TRUTH;
```

I recommended use of [Readonly](https://metacpan.org/pod/Readonly) instead.

```perl
use v5.10;

use Readonly;

Readonly::Scalar my $truth => 42;

say "The truth is $truth";
```

This gives us the best of both worlds:

- We have an immutable variable
- We can use it in a string interpolation

[Readonly](https://metacpan.org/pod/Readonly) comes with additional benefits, so if you by accident change the immutable variable your Perl application dies with the error (your application name and line number might vary).:

```
Modification of a read-only value attempted at immutable.pl line 11
```

Example:

```perl
#!/usr/bin/env perl

use strict;
use warnings;
use v5.10;

use Readonly;

Readonly::Scalar my $truth => 42;

$truth = 1;

say "The truth is $truth";
```

The policy [Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers](https://metacpan.org/pod/Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers) recommends the use of the [constant pragma](https://perldoc.perl.org/constant.html) or [Readonly](https://metacpan.org/pod/Readonly), but another related Perl::Critic policy is not recommending the use of the constant pragma, namely: [Perl::Critic::Policy::ValuesAndExpressions::ProhibitConstantPragma](https://metacpan.org/pod/Perl::Critic::Policy::ValuesAndExpressions::ProhibitConstantPragma). It's wide use easily demonstrates the _uglyness_ also as described in the examples above and in addition the [the documentation in Readonly](https://metacpan.org/pod/Readonly#Comparison-with-%22use-constant%22) makes compelling case. I have however always enjoyed Perl's constant pragma. I [wrote about this along time ago](https://lastmover.wordpress.com/2010/05/06/constant-vs-readonly/) and the actual write-up is no longer available and got lost at some point.

In order to explain it is time to redo the write-up. The constant pragma has one key benefit and that is the Perl compiler can optimize based on this. Let me demonstrate:

```perl
#!/usr/bin/env perl

use strict;
use warnings;
use v5.10;

use constant DEBUG => 1;

if (DEBUG) {
    print STDERR "Hello Happy World of Debugging\n";
}

exit 0;
```

Let the compiler back-end ([B](https://metacpan.org/pod/B)) and it's companions (B::Terse) do their bidding:

```bash
$ perl -MO=Terse constant_optimization.pl
LISTOP (0x7ff13f15cbe8) leave [1]
    OP (0x7ff13f15cb00) enter
    COP (0x7ff13f15cc30) nextstate
    LISTOP (0x7ff13f15cc90) scope
        COP (0x7ff13f15ccd8) null [193]
        LISTOP (0x7ff13f15cd38) print
            OP (0x7ff13ec0c8f8) pushmark
            UNOP (0x7ff13f15cdc8) rv2gv
                SVOP (0x7ff13ec0c8a0) gv  GV (0x7ff13f02ac38) *STDERR
            SVOP (0x7ff13f15cd80) const  PV (0x7ff13f8d0ab8) "Hello Happy World of Debugging\n"
    COP (0x7ff13f15cb48) nextstate
    UNOP (0x7ff13f15cba8) exit
        SVOP (0x7ff13ec0c938) const  IV (0x7ff13f8d0a70) 0
constant_optimization.pl syntax OK
```

But if set the constant to false (`0`):

```bash
> perl -MO=Terse constant_optimization.pl
LISTOP (0x7fac8f504b30) leave [1]
    OP (0x7fac8f89d780) enter
    COP (0x7fac8f89d6d8) null [193]
    OP (0x7fac8f504bc8) null [5]
    COP (0x7fac8f89d630) nextstate
    UNOP (0x7fac8f89d738) exit
        SVOP (0x7fac8f89d7c8) const  IV (0x7fac900554b8) 0
constant_optimization.pl syntax OK
```

The product is only 7 lines, the output of `Hello Happy World of Debugging` string is optimized out, where as the first version is 13 lines and includes the statements wrapping in our flow-control relying on the constant's value.

If we repeat the exercise using [Readonly](https://metacpan.org/pod/Readonly):

```perl
#!/usr/bin/env perl

use strict;
use warnings;
use v5.10;

use Readonly;

Readonly::Scalar my $DEBUG => 0;

if ($DEBUG) {
    print STDERR "Hello Happy World of Debugging\n";
}

exit 0;

```

Firstly we have with the immutable variable set to `0`

```bash
$ perl -MO=Terse readonly_optimization.pl
LISTOP (0x7fc797820e60) leave [1]
    OP (0x7fc797821df0) enter
    COP (0x7fc797820ea8) nextstate
    UNOP (0x7fc797820f08) entersub
        UNOP (0x7fc797820f80) null [158]
            OP (0x7fc797820f48) pushmark
            OP (0x7fc795c0c938) padsv [1]
            SVOP (0x7fc797820fc8) const  IV (0x7fc7970b16e0) 0
            UNOP (0x7fc795c0c8a0) null [17]
                SVOP (0x7fc795c0c8f8) gv  GV (0x7fc797895018) *Readonly::Scalar
    COP (0x7fc797821f20) nextstate
    UNOP (0x7fc797821f80) null
        LOGOP (0x7fc797821fc0) and
            OP (0x7fc797820e28) padsv [1]
            LISTOP (0x7fc797820c30) scope
                COP (0x7fc797820c78) null [193]
                LISTOP (0x7fc797820cd8) print
                    OP (0x7fc797820da8) pushmark
                    UNOP (0x7fc797820d68) rv2gv
                        SVOP (0x7fc797820de8) gv  GV (0x7fc79602ac38) *STDERR
                    SVOP (0x7fc797820d20) const  PV (0x7fc7970b19c8) "Hello Happy World of Debugging\n"
    COP (0x7fc797821e38) nextstate
    UNOP (0x7fc797821e98) exit
        SVOP (0x7fc797821ed8) const  IV (0x7fc7970b1a28) 0
readonly_optimization.pl syntax OK
```

Secondly we have with the immutable variable set to `1`

```bash
> perl -MO=Terse readonly_optimization.pl
LISTOP (0x7fcce402e060) leave [1]
    OP (0x7fcce402e7f0) enter
    COP (0x7fcce402e0a8) nextstate
    UNOP (0x7fcce402e108) entersub
        UNOP (0x7fcce402e180) null [158]
            OP (0x7fcce402e148) pushmark
            OP (0x7fcce3d09f48) padsv [1]
            SVOP (0x7fcce402e1c8) const  IV (0x7fcce512fef8) 1
            UNOP (0x7fcce3d09eb0) null [17]
                SVOP (0x7fcce3d09f08) gv  GV (0x7fcce5237418) *Readonly::Scalar
    COP (0x7fcce402e920) nextstate
    UNOP (0x7fcce402e980) null
        LOGOP (0x7fcce402e9c0) and
            OP (0x7fcce402e028) padsv [1]
            LISTOP (0x7fcce402de30) scope
                COP (0x7fcce402de78) null [193]
                LISTOP (0x7fcce402ded8) print
                    OP (0x7fcce402dfa8) pushmark
                    UNOP (0x7fcce402df68) rv2gv
                        SVOP (0x7fcce402dfe8) gv  GV (0x7fcce4822838) *STDERR
                    SVOP (0x7fcce402df20) const  PV (0x7fcce51301c8) "Hello Happy World of Debugging\n"
    COP (0x7fcce402e838) nextstate
    UNOP (0x7fcce402e898) exit
        SVOP (0x7fcce402e8d8) const  IV (0x7fcce5130228) 0
readonly_optimization.pl syntax OK
```

The output is very similar and no optimization is made, the value for the flow-control part is visible as either `0` or `1`, depending on what listing you are reading, but apart from that they are identical in number of lines and contents.

Conclusion: when you have parts of your code which could benefit from immutability, like _magic numbers_, use [Readonly](https://metacpan.org/pod/Readonly), When you however want to benefit from the compiler optimization use the [constant pragma](https://perldoc.perl.org/constant.html).

But as always with Perl, _There Is More Than One Way To Do It_ and [Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers](https://metacpan.org/pod/Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers) also points to [Const::Fast](https://metacpan.org/pod/Const::Fast) and according to the documentation for [Const::Fast](https://metacpan.org/pod/Const::Fast) it is an alternative to [Readonly](https://metacpan.org/pod/Readonly) - this would however require another blog post.

All code examples used in this post are available on [GitHub](https://github.com/jonasbn/blog-examples/tree/master/perls_constant_pragma_and_readonly_module)