leriksen has asked for the wisdom of the Perl Monks concerning the following question:

I am currently writing an perl OO based app, and I have written a small module which contains a number of constants, needed by separate disparate modules. This module looks something like
package App::Constants; # NOT its real name use constant MAX_PRIORITY => 10000; use constant DEFAULT_WIDTH => 7; use constant MSG_DATA => [ { # front ID_LT => 480, SEQ_LT => 481, }, { # back ID_LT => 810, SEQ_LT => 811, }, ]; use base qw(Exporter); our @EXPORT_OK = qw(MAX_PRIORITY DEFAULT_WIDTH MSG_DATA); our %EXPORT_TAGS = (default => \@EXPORT_OK); 1;
I need to loop over the hashes in MSG_DATA at one point in my code. And to do this , my code looks like
package App::Document; use App::Constants qw(default); sub apply { foreach my $msg (@{&MSG_DATA}) { some_func($msg->{ID_LT}); } } 1;
Note the little & before the constant MSG_DATA - it is required under 'use strict;', otherwise you get an error about ambiguous usage or symbolic reference or any number of problems. You can also get the 'right' actions if you use
@{+MSG_DATA}; # syntactic separation with unary plus @{MSG_DATA()}; # function that returns reference to array
My concern is that the &MSG_DATA and MSG_DATA() usages betray the fact that I know the current implementation of the constant.pm module uses subroutines internally - and this is an implementation detail I would prefer not to exploit, as future change will break my code (unless that change is backwards compatible, which I dont want to bet on either). And the +MSG_DATA usage is somewhat obscure, leading to possible maintenance problems in the future for whoever looks after this after me.

So the question is, is there a better way to use a constant data structure like this, that protects against future implementation changes and is obvious to a moderately knowledgable perl'er.


+++++++++++++++++
/#!/usr/bin/perl use warnings; use strict; use brain;

Replies are listed 'Best First'.
Re: looping over constant data structure references
by blokhead (Monsignor) on Nov 11, 2003 at 04:53 UTC
    Constants using the constant pragma need not be scalars, they can be arrays lists too:
    use Data::Dumper; use constant MSG_DATA => { foo => 1 }, { bar => 2 }, { baz => 3 }; for my $msg (MSG_DATA) { print Dumper $msg; }
    Use [ MSG_DATA ] elsewhere in the code if you need to use the list as an reference.

    Incidentally, this feature is the source of many accidental bugs with constant:

    use constant FOO => "xyz", BAR => "def", BAZ => "abc"; # FOO returns qw/xyz BAR def BAZ abc/ # BAR and BAZ aren't defined as constants
    The programmer probably meant to declare three constants, not one:
    use constant { FOO => "xyz", BAR => "def", BAZ => "abc" };

    blokhead

      thanks , I'll ponder on that one - it does seem better - a list matches the constant idea better - contents of constant references are mutable, so removing the []'s removes that level of writable-ness, if that's the right term.

      I'd worry about the [MSG_DATA] though - this copies MSG_DATA and returns a reference to the copy - this may or may not be what you want.
      +++++++++++++++++
      #!/usr/bin/perl use warnings; use strict; use brain;
Re: looping over constant data structure references
by Aristotle (Chancellor) on Nov 11, 2003 at 06:45 UTC
    Future compatibility is not really an issue at least if you stick to Perl5, but if you're really that nervous about it, how about @{(MSG_DATA)} ? Note also that @{&MSG_DATA} will disable Perl's constant sub optimization (and will make it possible (if unlikely) for the value to change at runtime if the sub is redefined, as well).

    Makeshifts last the longest.