The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

use 5.008001;
use strict;
our $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)/g;
use Data::Lock ();
sub UNIVERSAL::Constant : ATTR {
my ( $pkg, $sym, $ref, $attr, $data, $phase ) = @_;
(
ref $ref eq 'HASH' ? %$ref
: ref $ref eq 'ARRAY' ? @$ref
: ($$ref)
)
= ref $data
? ref $data eq 'ARRAY'
? @$data # perl 5.10.x
: $data
: $data; # perl 5.8.x
Data::Lock::dlock($ref);
}
1;
__END__
=head1 NAME
Attribute::Constant - Make read-only variables via attribute
=head1 VERSION
$Id: Constant.pm,v 1.1 2013/04/03 14:37:57 dankogai Exp $
=head1 SYNOPSIS
use Attribute::Constant;
my $sv : Constant( $initial_value );
my @av : Constant( @values );
my %hv : Constant( key => value, key => value, ...);
=head1 DESCRIPTION
This module uses L<Data::Lock> to make the variable read-only. Check
the document and source of L<Data::Lock> for its mechanism.
=head1 ATTRIBUTES
This module adds only one attribute, C<Constant>. You give its
initial value as shown. Unlike L<Readonly>, parantheses cannot be
ommited but it is semantically more elegant and thanks to
L<Data::Lock>, it imposes almost no performance penalty.
=head1 CAVEAT
=head2 Multi-line attributes
Multi-line attributes are not allowed in Perl 5.8.x.
my $o : Constant(Foo->new(one=>1,two=>2,three=>3)); # ok
my $p : Constant(Bar->new(
one =>1,
two =>2,
three =>3
)
); # needs Perl 5.10
In which case you can use L<Data::Lock> instead:
dlock(my $p = Bar->new(
one => 1,
two => 2,
three => 3
)
);
After all, this module is a wrapper to L<Data::Lock>;
=head2 Constants from Variables
You may be surprised the following code B<DOES NOT> work as you expected:
#!/usr/bin/perl
use strict;
use warnings;
use Attribute::Constant;
use Data::Dumper;
{
package MyClass;
sub new {
my ( $class, %params ) = @_;
return bless \%params, $class;
}
}
my $o = MyClass->new( a => 1, b => 2 );
my $x : Constant($o);
print Dumper( $o, $x );
Which outputs:
$VAR1 = bless( {
'a' => 1,
'b' => 2
}, 'MyClass' );
$VAR2 = undef;
Why? Because C< $x : Constant($o) > happens B<before>
C<< $o = Myclass->new() >>.
On the other hand, the following works.
my $y : Constant(MyClass->new(a => 1,b => 2));
print Dumper( $o, $y );
Rule of the thumb is do not feed variables to constant because
varialbes change after the attribute invocation.
Or simply use C<Data::Lock::dlock>.
use Data::Lock qw/dlock/;
dlock my $z = $o;
print Dumper( $o, $y );
=head1 SEE ALSO
L<Data::Lock>, L<constant>
=head1 AUTHOR
Dan Kogai, C<< <dankogai+cpan at gmail.com> >>
=head1 BUGS & SUPPORT
See L<Data::Lock>.
=head1 ACKNOWLEDGEMENTS
L<Readonly>
=head1 COPYRIGHT & LICENSE
Copyright 2008-2013 Dan Kogai, all rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.