http://www.perlmonks.org?node_id=75904

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

C was my first language, and in my C class (and to a greater extent later in C++), I learned the importance of const and its use in creating safe code. I've been using perl now for about a year, and couldn't be happier. Perl is... well... you folks know the joy I'm feeling :)

At any rate, I was wondering... It seems that a lot of people use something like:
    my $filename = "/path/to/file/to/munge";

whereas I've been using something like:
    use constant FILENAME => '/path/to/file/to/munge';

Are there any advantages to using the former over the latter, provided the data doesn't get altered throughout the execution of the program? Am I in error to use a large number of constants at the beginning of a program to do configuration as opposed to local variables? Please enlighten! :)

Edit: chipmunk 2001-04-26

Replies are listed 'Best First'.
(Ovid constants) Re: my $var; vs. use constant VAR = '';
by Ovid (Cardinal) on Apr 27, 2001 at 01:08 UTC
    The second method is better defensive programming. However, what it does is pretty much equivalent to the following:
    BEGIN { sub FILENAME() { '/path/to/file/to/munge' } }
    Because FILENAME is actually a subroutine, it cannot be interpolated in quotes. In other words, the following are not synonymous:
    my $filename = "/path/to/file/to/munge"; print "$filename"; use constant FILENAME => '/path/to/file/to/munge'; print "FILENAME";
    The first example prints the filename, the second just prints "FILENAME".

    That's a minor issue, but it does crop up from time to time (particularly when I'm writing an open X, Y or die statement).

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: my $var; vs. use constant VAR = '';
by tadman (Prior) on Apr 27, 2001 at 01:07 UTC
    'use constant' doesn't appear to be terribly popualar, as 'my' does effectively the same thing, without the child-proof safety locks that prevent you from modifying variables declared that way.

    Instead of declaring a whole whack of constants using my(), such as:
    my ($filename) = "/path/to/file"; my ($filemode) = "immolate"; my ($opmode) = "seek"; my ($filetype) = "image/gif";
    You could always convert this to a hash-structure, such as:
    my (%config) = ( filename => "/path/to/file", filemode => "immolate", opmode => "seek", filetype => "image/gif", );
    This has the advantage of allowing you to declare virtually unlimited constants, without having to explicitly declare them on their own my() line. Additionally, you can load these from a file quickly and easily (i.e. an INI-type file, an Apache-style file, or something else) such that you can vary the configuration without modifying the program itself.

    Of course, using a hash-lookup is slower than a regular variable, but the price you pay would depend on frequency of use, and in practice, should be so slight as to really be irrelevant. In most cases where a constant is used frequently, such as inside a loop, you would expect to see something like:
    my ($thing) = $config{'thing_to_mash'}; for (my $x = 0; $x < 100_000_000; $x++) { DoCrazyStuff($thing, $x, Foo($x)); }
    In this admittedly simple example, the hash is only used once, and the variable itself is repeatedly used.

    If you really don't trust yourself to keep your const's constant, and to not modify them in any way, write a function to extract parameters from it, such as:     sub Config { return $config{$_[0]}; } Then you could keep %config in some sort of codeblock or module which nobody has access too. This is kind of extreme, though.
      my ($filename) = "/path/to/file"; my ($filemode) = "immolate"; my ($opmode) = "seek"; my ($filetype) = "image/gif";
      As a matter of style (and occasionally necessity), I leave off the parens on those leftsides if the right side needs to be evaluated in a scalar context. Otherwise, I might wonder which one you meant of:
      my ($filemode) = ("immolate"); # list context
      or
      my $filemode = "immolate"; # scalar context
      And yes, it really does matter when you get into subroutine arg grabbing, like
      my $count = @_; # get the length
      or should that have been
      my ($count) = @_; # get the first arg
      So, make your left side and your right side agree, and I don't have to scratch my head wondering where you are headed.

      -- Randal L. Schwartz, Perl hacker

        Letting go of brackets is hard if you come from the C school of bondage and discipline programming, where forgetting something minor, like brackets on a function call, is punishable by death ("Segmentation fault.").

        When declaring arguments, I have found that the code looks strange, inconsistent, and a little off-kilter when mixing and matching declaration styles, where 'off-kilter' is a euphemism for "looks broken":
        sub Foo { # Arguments: ARRAY <- ARRAY my ($ich, $bin) = @_; # Local variables: SCALAR,SCALAR,... my $x, $y, $z; # Local constants: ARRAY <- ARRAY my ($ein, $berliner) = qw [ jelly donut ]; # Single constant: SCALAR <- SCALAR my $go = 5; }
        Any statement like 'my $count = @_' can make me feel a little bit dizzy, if only because it seems like anything could happen there (i.e. concatenation with spaces, concatenation without, first element assignment, last element assignment, count of items, index of last item, etc.). Instead, I would rather explicitly specify what is intended as 'my ($count) = scalar (@_);', though rumor would have it that 'scalar' is deprecated.

        Anyway, maybe I'm just behind the times. I use brackets on int() and join(). I'll admit it! Maybe it's curable. As long as I'm careful to make sure that my assignments are array-safe (as I don't want to go to jail) then things work okay, in their own wacky way, and everything is bracketized and compartmentalized neatly.

        So, I can only suppose that you would prefer the following mutant variation, suggested for fun:
        my $filename = "/path/to/file", $filemode = "immolate", $opmode = "seek", $filetype = "image/gif";
Re: my $var; vs. use constant VAR = '';
by satchboost (Scribe) on Apr 27, 2001 at 01:07 UTC
    Personally, I don't use constants. However, I work on a relatively large project with over 1000 files. That means that hiding my globals in modules that inherit Exporter tends to be more efficient for me. (And, easier to maintain, to boot!)

    That said, by using use constant, you are being purer, in a sense. You're giving more information to the reader of your code as to exactly what's going to happen in the rest of the code. This is a good thing.

    That said ... unless you are absolutely positive about the lifetime scope of what you're working on, I'd tend to shy away from constants. Let's say you're working on something that takes information from a number of Perl modules (like parent, children, function names, etc) and makes a bunch of HTML pages from it. Initially, you're going to be working with a small set of files, so making a bunch of stuff constant, like the base directory, makes sense. However, your project grows. You start to realize that you want to allow for greater flexibility. Maybe you don't think that you can change the constants, so your development possibilities are restricted. This sounds far-fetched, but it really isn't.

    I conceive of constants as things that can never change, no matter how my script/tool/app changes. Things like PI, E, etc. I don't care what happens to what I've written, but PI isn't changing. That's a good choice for a constant. Making a filename a constant means that you have to alter your code significantly if you want to allow users to pass the filename into the script. That's a design that wasn't thinking ahead.

    Just my $0.02.

Re: my $var; vs. use constant VAR = '';
by Rhandom (Curate) on Apr 27, 2001 at 01:55 UTC
    Something that will let you use scalars but will prevent them being modified:
    my $const = \"Don't touch me!"; my $num = \5.6; local *const2 = \"Another string"; local *num2 = \3.14159; print "[$$const][$$num][$const2][$num2]\n"; ### try and modify it eval{ $num2 = 3; }; print $@; print "$num2\n";

    The first ones are not as pretty as dollar variables, and the second have a slight overhead of local, but I think that should give you some nice unmodifiable variables.

    UPDATE:
    Benchmarks are always good. Read em and weep:
    #!/usr/bin/perl -w use Benchmark qw(timethese cmpthese countit timestr); use constant CONST_MOD => 3; sub CONST_SUB () { 3 }; my $const_my = 3; local $const_local = 3; my $const_ref = \3; local *const_alias = \3; print "mod[".CONST_MOD."]sub[".CONST_SUB."]\n" ."my[$const_my]local[$const_local]\n" ."ref[$$const_ref]alias[$const_alias]\n"; cmpthese (1_000_000, { CMod => sub { my $t = CONST_MOD }, CSub => sub { my $t = CONST_SUB }, CMy => sub { my $t = $const_my }, CLocal => sub { my $t = $const_local }, CRef => sub { my $t = $$const_ref }, CAlias => sub { my $t = $const_alias }, });
    Produces the following:
    mod[3]sub[3] my[3]local[3] ref[3]alias[3] Benchmark: timing 1000000 iterations of CAlias, CLocal, CMod, CMy, CRe +f, CSub... CAlias: 0 wallclock secs ( 0.79 usr + 0.00 sys = 0.79 CPU) @ 12 +65822.78/s (n=1000000) CLocal: 0 wallclock secs ( 0.80 usr + 0.00 sys = 0.80 CPU) @ 12 +50000.00/s (n=1000000) CMod: 2 wallclock secs ( 0.80 usr + 0.00 sys = 0.80 CPU) @ 12 +50000.00/s (n=1000000) CMy: 1 wallclock secs ( 0.75 usr + 0.00 sys = 0.75 CPU) @ 13 +33333.33/s (n=1000000) CRef: 0 wallclock secs ( 1.03 usr + 0.00 sys = 1.03 CPU) @ 97 +0873.79/s (n=1000000) CSub: 0 wallclock secs ( 0.81 usr + 0.01 sys = 0.82 CPU) @ 12 +19512.20/s (n=1000000) Rate CRef CSub CLocal CMod CAlias CMy CRef 970874/s -- -20% -22% -22% -23% -27% CSub 1219512/s 26% -- -2% -2% -4% -9% CLocal 1250000/s 29% 3% -- -0% -1% -6% CMod 1250000/s 29% 3% 0% -- -1% -6% CAlias 1265823/s 30% 4% 1% 1% -- -5% CMy 1333333/s 37% 9% 7% 7% 5% --
    The only noticable differences are the my and the ref. The reference takes too long, the "my" is a little quicker but it is modifiable. All of the others are neck a neck, so, I'd vote for local *var=\23;

    my @a=qw(random brilliant braindead); print $a[rand(@a)];
      Ah, the perils of benchmarking... my results from v5.6.1 on Linux:
      Rate CRef CAlias CMy CLocal CMod CSub CRef 2702703/s -- -8% -22% -22% -24% -27% CAlias 2941176/s 9% -- -15% -15% -18% -21% CMy 3448276/s 28% 17% -- -0% -3% -7% CLocal 3448276/s 28% 17% 0% -- -3% -7% CMod 3571429/s 32% 21% 4% 4% -- -4% CSub 3703704/s 37% 26% 7% 7% 4% --
      and then the same program, run just a second later:
      CAlias 2857143/s -- -0% -3% -6% -20% -23% CRef 2857143/s 0% -- -3% -6% -20% -23% CMod 2941176/s 3% 3% -- -3% -18% -21% CSub 3030303/s 6% 6% 3% -- -15% -18% CLocal 3571429/s 25% 25% 21% 18% -- -4% CMy 3703704/s 30% 30% 26% 22% 4% --
         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print
        Don't worry, I had that happen on mine as well, but in every case, the my was a percentage faster and the ref was a percentage slower and everything else just hummed around in the middle. The point wasn't the benchmark. The point was that declaring aliases or setting up your own constant subs, are not that much slower than my'ing a variable or local'ing a variable.

        The point of benchmark is ballpark, and all of the types are in the ball park.

        my @a=qw(random brilliant braindead); print $a[rand(@a)];
Re: my $var; vs. use constant VAR = '';
by arturo (Vicar) on Apr 27, 2001 at 01:06 UTC

    From perldoc constant

    "These constants do not directly interpolate into double-quotish strings, although you may do so indirectly."

    There might be a bit of a performance hit when using the constants approach, but I doubt it's *huge* and you are protected from accidentally altering your constants.

    "edited" by (arturo) hisself ... sorry, I thought I'd broken the lines up correctly and it showed up fine in my browser.

      Actually constants are faster, since use constant simply turns them into constant subs (for versions of Perl that support this):
      sub CONST_NAME () { 'value' }
      IIRC, this form is optimized by the Perl compiler such that there are no hits to the symbol table in dereferencing the value; it would be as if you typed the constant value in as a literal, much like a preprocessor #DEFINE macro.

      update: Looks like I was wrong, my variables are actually a hair faster than both constants and even literal values.

         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print
Re: my $var; vs. use constant VAR = '';
by antihero (Novice) on Apr 27, 2001 at 00:59 UTC
    eeek... I just noticed that I borked the title... it was meant to read

    my $var =""; vs. use constant VAR => '';
      Something that is just as fast (slightly faster) than use constant, that can be localized, and that is neat, is to create a reference or alias to a non modifiable variable. Try this:
      local *CONST = \23.34234334234;
      Try to modify it. You can't. Declare it at the top of your program and it is there for life. Put it in a sub and it stays around for the life of the sub. See 75935 buried way at the bottom of this node.

      my @a=qw(random brilliant braindead); print $a[rand(@a)];