Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Perl "Constants"

by zerohero (Monk)
on Jul 07, 2009 at 01:34 UTC ( [id://777711]=perlquestion: print w/replies, xml ) Need Help??

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

I'd like to have read-only constants which exist in a module that I include. The purpose of the constant is to eliminate "magic numbers", as one would do with a #define in C.

What I've been doing, which has some drawbacks, is to make a module with Exporter and do the following, and then import each constant into the package it's used in.

package MyConstants; use base qw (Exporter); our @EXPORT_OK = qw (SOME_CONSTANT); + use constant SOME_CONSTANT => 'the value';

Is there a better method than this? This suffers the drawback that inside of a hash, it doesn't get interpolated (i.e. $h{SOME_CONSTANT} doesn't behave as one would "like").

Replies are listed 'Best First'.
Re: Perl "Constants"
by GrandFather (Saint) on Jul 07, 2009 at 01:54 UTC

    Readonly may help.


    True laziness is hard work
Re: Perl "Constants"
by perrin (Chancellor) on Jul 07, 2009 at 03:55 UTC
    Forget the constant pragma. The minor speed difference over a variable isn't worth the bugs it causes when you accidentally use it in a context where it doesn't interpolate. Just use $SOME_CONSTANT instead.
Re: Perl "Constants"
by tprocter (Sexton) on Jul 07, 2009 at 02:34 UTC

    If you want to continue using constant, and you want to interpolate within a string, the only way I know of is using the array interpolations:

    use constant SOME_CONSTANT => 'the value'; print "This is @{[SOME_CONSTANT]}\n";

    Within a hash key, treat it as a sub:

    $h{&SOME_CONSTANT} = 'hash value';

      For string interpolation you may also use scalar context

      print "This is ${\SOME_CONSTANT}\n";

      With a hash key you can also disambiguate a constant with parens

      $h{(SOME_CONSTANT)}
Re: Perl "Constants"
by JavaFan (Canon) on Jul 07, 2009 at 07:19 UTC
    I used to use use constant; because that felt like being the "right" way. But I got annoyed by the constants not behaving like variables you don't modify. (Don't interpolate, can be autoquoted). So, I haven't used use constant; for a long time now. I use variables, whose name I usually uppercase.
      "use constant" is useful for debug statements and levels. In recent versions of Perl, if the compiler can see say "if DEBUG_LEVEL3" and if knows that DEBUG_LEVEL3 is false, that statement will not even be compiled. This can result in a significant performance increase where there are lots of detailed "debug" print statements within an inner loop.

      Other than that, I think use constant is pretty worthless. I normally use a 'C' style $ALL_UPPER_CASE for constants and as a matter of programming discipline, never use something like that as a lvalue.

      I guess that was a long winded way of saying: I agree, but think about constant for debug flags when you have a lot of them or they are in performance critical sections of code.

Re: Perl "Constants"
by Marshall (Canon) on Jul 07, 2009 at 07:14 UTC
    In 'C', yes there can be many #define statements.

    One way to deal with this in Perl is to say have a .ini file. Stick these "magic" definitions like "MAX_RECS_PER_LINE = 8" in that file. Parsing a .ini file can get to be a pretty big deal in 'C'. In Perl, this is easy as there are a number of "config" modules that do that. At times I have built a "front-end" module that uses some flavor of the configuration .ini modules.

    Anyway one possibility is to have say $MAX_RECS_PER_LINE as a program variable and you ask the config module (really a mini read only DB in simple case) what MAX_RECS_PER_LINE means.

Re: Perl "Constants"
by Arunbear (Prior) on Jul 07, 2009 at 16:24 UTC
    You can also create a constant like this:
    *SOME_CONSTANT = \ 'the value';
    Then these will be possible:
    $h{$SOME_CONSTANT}; print "$SOME_CONSTANT\n";
    but
    $SOME_CONSTANT = 'new value';
    would die with "Modification of a read-only value attempted at ... ".

    This is documented in perlmod under "Symbol Tables".

      Small problem is that these are package variables (not 'my'-able). Under 'use strict' U have to 'our' them. In case U want the freedom to choose between package or lexical, I use this:
      use CONSTANT; CONSTANT my $E => 2.73, my $PI => 3.14, my $CREDO => 'The dream of the slave is...to become master +and have slaves'; # Oops! Wrong CREDO ;) $CREDO = 'In $$$ we trust!'; # will ERROR out ;) # and U can: print "I still believe that '$CREDO!'\n"; #where package CONSTANT; use Carp; use Exporter; use Tie::Scalar; @ISA = qw(Tie::StdScalar Exporter); @EXPORT = qw(CONSTANT); # sub CONSTANT {my $i=0;tie $_[$i++],__PACKAGE__,$_[$i++] while $i<@_} sub CONSTANT {tie $_[$.++],__PACKAGE__,$_[$.++] while $. < @_} # If you want to know if something is tied somewhere ;) # sub REF {@_ > 1 ? '' : ref tied $_[0] || ref $_[0]} sub STORE {confess "constants are READ ONLY!"}; 1; vess

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://777711]
Approved by AnomalousMonk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-26 05:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found