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

Monks,

I need to use constants that are (a) usually numeric, and (b) often included in text sent to the user. Of the WTDI I'm sure there are many, but I've found two, and I hope there are better ones.

Method numero uno uses use constant. An advantages is that everything looks like a constant; a disadvantage is that the dot construct looks kind of ugly.

use constant MIN_CHAR => scalar 1; use constant MAX_CHAR => scalar 12; print 'x '.MIN_CHAR.'-'.MAX_CHAR.' x';

Method numero two uses a hash. An advantage is that there's no dot concatenation; a disadvantage is that they don't look much like constants anymore.

my %constants = ( min_char => 1, max_char => 12 ); print "x $constants{'min_char'}-$constants{'max_char'} x";

Left to my own devices, I'd use the first. The dots are ugly, but at least I'm using constants like constants. Does anyone have a better method?

Thanks
--
man with no legs, inc.

Replies are listed 'Best First'.
Re: Use constant vs. hashes
by MeowChow (Vicar) on Jul 03, 2001 at 07:20 UTC
    This topic was covered just yesterday as a snippet. Try it this way:
    use constant MIN_CHAR => 1; # no need to put a 'scalar' in front use constant MAX_CHAR => 12; print "x ${\MIN_CHAR}-${\MAX_CHAR}";
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
Re: Use constant vs. hashes
by bikeNomad (Priest) on Jul 03, 2001 at 08:14 UTC
    Another solution might be to protect ordinary scalars using a tie:

    use strict; package ConstantScalar; use Carp; require Tie::Scalar; @ConstantScalar::ISA = 'Tie::StdScalar'; sub STORE { confess "illegal store into constant"; } # call with a list of refs to scalars sub makeConstant { while (my $ref = shift) { (warn "nonscalar ref", next) if (ref($ref) ne 'SCALAR'); tie $$ref, 'ConstantScalar', $$ref; } } package main; my ($A, $B, $C, $D) = (1, 2, 3, 4); my $E = 5; print "$A $B $C $E\n"; ConstantScalar::makeConstant(\($A, $B, $C, $D)); $E = 123; $A = 4; # illegal store into constant $B = 5; print "$A $B $C $E\n";
      This is one I developed seperately with more stuff in it, also allowing constant hashes and arrays (much like tuples in python as I understand them). It also uses a different and IMHO cleaner syntax for creating the constants:
      Const my $foo => 42;

      Here's the sample program:

      #!/usr/bin/perl -w use strict; use Const qw/Const ConstHash ConstArray/; Const my $FOO => 42; # tie my $FOO, 'Const', 42; print "$FOO\n"; # prints "42" $FOO = 43; # croaks for attempted change $FOO++; # same ConstHash my %BOO => { foo => 'blah', moo => 41, 2 => 'no' }; # tie my %BOO, 'ConstHash', { foo => 'blah', moo => 41, 2 => 'no' }; print "$BOO{foo} $BOO{2}\n"; # prints "blah no" $BOO{moo}++; # croaks for attempted change %BOO = (); # same print "$BOO{Foo}\n"; # croaks for non-existant element ConstArray my @MOO => [ qw/foo 2 five seven/ ]; # tie my @MOO, 'ConstArray', [ qw/foo 2 five seven ]; print "$MOO[0] $MOO[3]\n"; # prints "foo seven" $MOO[1]++; # croaks for attemped change $MOO[5] = 2; # same splice(@MOO,1,1,4); # same again print "$MOO[10]\n"; # croaks for non-existant element
      And the implementation in Const.pm (click Read More)
        Thanks to everyone - some great ideas here. And, as I'd hoped, a couple that I hadn't thought of :)
        --
        man with no legs, inc.
      ++{the idea}, but here's another WTDI.
      package Fixed; use Carp; use strict; sub TIESCALAR { my ($class, $value) = @_; croak "No value provided for new Fixed scalar" unless defined $value; bless \$value, $class; } sub FETCH { return ${$_[0]}; } sub STORE { croak "Illegal assignment to Fixed scalar"; } package main; tie my $v, "Fixed" => "32"; tie my $x, "Fixed" => "0"; tie my $str, "Fixed" => "my string"; print ">> $v\n"; $v++; print ">> $v\n";

      -- Frag.

Re: Use constant vs. hashes
by tachyon (Chancellor) on Jul 03, 2001 at 06:20 UTC

    A 'constant' is useful - perhaps - because you can't accidentally change it. Method 1 achieves this, whereas method two is no more 'constant' than: my ($min_char, $max_char) = (1,12);

    You are free to change the values of your %constant hash anywhere within its lexical scope. The only advantage of your method 2 is the implicit "Don't change these, they are constants" nomenclature of the hash. You can use a sub to generate a 'constant' like this:

    sub MIN { return 1 } sub MAX { return 12 }

    This generates 'constants' but suffers from the same formatting woes as use constant in that you can't interpolate a sub into a double quoted string. You may like this formatting using printf more:

    sub MIN { 1 } # could just as easily be 'use constant MIN => 1;' sub MAX { 12 } printf "x %d - %d x", MIN, MAX;

    I have dropped the return as a sub returns the last value it evaluates and I am inherently lazy.

    Otherwise use normal lexically scoped variables to make it pretty:

    my ($min, $max) = (1,12); print "x $min - $max x";

    These are your choices, it's up to you what you prefer. One of the common conventions is to use ALL_CAPS for constants which is important if these constants are actually variables and we are depending on programmer goodwill not to change them. Swings and roundabouts. TIMTOWDI

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n\w+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Use constant vs. hashes
by John M. Dlugosz (Monsignor) on Jul 03, 2001 at 07:53 UTC
    I don't like losing the interpolation ability, one of the main features of Perl! I'll use a variable, and long for Perl 6 to be available with is constant.

    Today, someone could make a patch to check for assignments to ALL_CAP my's, and using the naming convention means not having to alter the parser.

    —John

Re: Use constant vs. hashes
by legLess (Hermit) on Jul 03, 2001 at 06:04 UTC
    Of course, I could just use
    my $MIN_CHAR = 1; my $MAX_CHAR = 12; print "x $MIN_CHAR-$MAX_CHAR x";
    Best of both worlds, or ugly kludge?
    --
    man with no legs, inc.