NAME

readonly - Perl pragma to declare readonly scalars

SYNOPSIS

use readonly '$READONLY' => 57 ;
use readonly '$TOPIC'    => 'computing' ;
use readonly '$TRUE'     => 1 ;
use readonly '$FALSE'    => 0 ;
use readonly '$PI'       => 4 * atan2 1, 1 ;

use readonly
        '$ALPHA'    => 1.761,
        '$BETA'     => 2.814,
        '$GAMMA'    => 4.012,
        '$PATH'     => '/usr/local/lib/lout/include',
        '$EXE'      => '/usr/local/bin/lout',
        ;

use readonly '$BASE' => '/usr/opt/mozilla' ;
# Have to use a separate readonly if we refer back.
use readonly
        '$RC'   => "$BASE/config",
        '$EXE'  => "$BASE/bin",
        ;

DESCRIPTION

This pragma creates readonly scalars in the current namespace. The scalars thus created may be used in all contexts where read/write scalars would be used with the exception that you will get an eval trappable run-time error "Modification of a read-only value attempted..." if you try to assign to a readonly scalar.

Of course there is already a pragma, constant, which provides this kind of functionality (and more, since constant also handles arrays, hashes etc). However constants must be used with different syntax in different contexts, whereas readonlys can be used with the same consistent scalar syntax throughout.

String interpolation

use constant PI    => 4 * atan2 1, 1 ;
use readonly '$PI' => 4 * atan2 1, 1 ;

We cannot print constants directly so we must do this:

print "The value of pi is ", PI, "\n" ;

or this:

print "The value of pi is @{[PI]}\n" ;

but we can print readonlys directly:

print "The value of pi is $PI\n" ;

Hash keys

use constant TOPIC    => 'geology' ;
use readonly '$TOPIC' => 'geology' ;

my %topic = (
        geology   => 5,
        computing => 7,
        biology   => 9,
    ) ;

If we try to access one of the hash elements using the constant:

my $value = $topic{TOPIC} ;

we get an unwelcome surprise: $value is set to undef because perl will take TOPIC to be the literal string 'TOPIC' and since no hash element has that key the result is undef. Thus in this situation we would have to write:

my $value = $topic{TOPIC()} ;

or perhaps:

my $value = $topic{&TOPIC} ;

On the other hand if we use a readonly scalar we can simply write:

my $value = $topic{$TOPIC}

with no problems.

Error reporting

PI = 3 ;

will lead to a compile-time error, "Can't modify constant item in scalar assignment...", whereas

$PI = 3 ;

will lead to a run-time error, "Modification of a read-only value attempted...".

Is it necessary?

You can achieve the same effect as:

use readonly '$WEB_ADDRESS' => 'www.perlpress.com' ;

by coding:

use vars '$WEB_ADDRESS' ; *WEB_ADDRESS = \'www.perlpress.com' ;

Similarly:

use constant WEB_ADDRESS => 'www.perlpress.com' ;

can be coded as:

sub WEB_ADDRESS() { 'www.perlpress.com' } # No semi-colon.

However, readonly allows us to create many readonly scalars in one go with a compact syntax:

use readonly
        '$HOME' => '/home/summer',
        '$ROOT' => '/root',
        '$PERL' => '/usr/lib/perl',
        ;

BUGS

Only copes with scalars.

Strings which contain \'s will have them removed.

Silently ignores attempted redeclarations, e.g.

use readonly '$READONLY' => 5 ;
...
use readonly '$READONLY' => 9 ;

$READONLY is still 5, but no error message is given.

AUTHOR

I copied some ideas from constant.pm.

Mark Summerfield. I can be contacted as <summer@perlpress.com> - please include the word 'readonly' in the subject line.

COPYRIGHT

Copyright (c) Mark Summerfield 2000. All Rights Reserved.

This module may be used/distributed/modified under the same terms as perl itself.