use constant will surprise you with its evil.

Let’s say you have some perl code that seems nice and normal:

It defines a constant, and then you use it. It should work fine, right? No. In perl, use constant just makes a sub for that word that when evaluated will return the value, it’s not a “real constant” in a way which other languages have constants. This will fail you whenever you are trying to interpolate or in a hash or basically anywhere.

I genuinely can’t imagine a scenario in which ‘use constant’ would be useful to me.

UPDATE: I’d like to add that the way I’d rather deal with this problem is:

About these ads
This entry was posted in tech and tagged . Bookmark the permalink.

21 Responses to use constant will surprise you with its evil.

  1. fallous says:

    Fat quote is dealing with a bareword and thus turning it into a literal-quoted string. my %foo = (MY_CONSTANT() => ‘dingle’) or +MY_CONSTANT=>’dingle’ does the right thing.

  2. fallous says:

    What if you define *MY_CONSTANT=13 instead?

    • earino says:

      You’ll have to excuse me, I don’t understand what you are asking me to do :)

      • fallous says:

        I was thinking about how you could do it with typeglobs, but as the Readonly module mentions that’s got its own share of pain.
        I don’t use constant for anything so I’ve never had to encounter its rather poor bolted-on behavior.

  3. You are missing the point of constant folding here:

    use warnings;
    use strict;
    
    use Data::Dumper;
    $Data::Dumper::Deparse = 1;
    
    use Readonly;
    
    Readonly my $semi_constant => 13;
    
    use constant proper_constant => 13;
    
    warn Dumper {
      shortcircuit_semi => sub { $semi_constant ? 42 : 0 },
      shortcircuit_proper => sub { proper_constant ? 42 : 0 },
      branch_nonfolding => sub { $semi_constant or do_stuff() },
      branch_folding => sub { proper_constant or do_stuff() },
    };
    

    Cheers

    • earino says:

      Greetings!

      I do believe I understand how constant folding works, and it’s one heck of an awesome technique that modern compilers and interpreters use… I however don’t believe that it negates the point of my blog post. What I am complaining about is that the behavior of ‘use constant’ will surprise folks.

      If this example doesn’t surprise you, then I believe you and I have different thresholds of surprise:

      #!/usr/bin/env perl
      
      use warnings;
      use strict;
      use Data::Dumper;
      
      use constant MY_CONSTANT => "key";
      
      my %foo = ();
      $foo{MY_CONSTANT} = MY_CONSTANT;
      
      print Dumper \%foo;
      

      Cheers :)

  4. Also, please use Const::Fast instead of Readonly, unless you really like ties :-(

  5. Pingback: More on constants in perl | Ed's Blog

  6. See http://neilb.org/reviews/constants.html for a comparison of various CPAN modules for defining constants.

    If you are in a hurry, skip to the Conclusion section. Neil concludes that for his application he switched from Readonly to Const::Fast (as Leon T. suggested above).

  7. b2gills says:

    You have to tell Perl that you want to use a subroutine.

    my %foo = (MY_CONSTANT() => ‘dingle’);
    my %foo = (MY_CONSTANT, ‘dingle’);
    my %foo = (+MY_CONSTANT => ‘dingle’);

    The point of => is to change the token before it into a string.

  8. ysth says:

    Yes, there is a surprise here, one of a few Perl has in store for newcomers. But it should only happen once per programmer; instead of learning to not use constant, learn to use () after the constant name.

    (Though I’d be in favor of new warnings for the MYCONSTANT => and $foo{MYCONSTANT} cases.)

  9. You can use fat comma to get rid of stringification:
    use constant MY_CONSTANT => 13;
    my %foo = (MY_CONSTANT ,=> ‘dingle’);
    But constant module has other problems and side effects anyway.

  10. barefootcoder says:

    Hey, Ed.

    So, like everyone else says: don’t use constant for constants. :-) Use constant for conditional compilation. (For instance, check out my module Debuggit for a good use of that technique.) Use Const::Fast for constants.

    It’s counter-intuitive, true. But now you know. And knowing is half the battle. Also, knowing that knowing is half the battle is three-quarters of the battle. ;->

    • earino says:

      It is counter intuitive :( That’s what makes me sad-face. The net migration of mindshare for perl is probably not positive, and when something as simple in other languages as a *constant* is counter intuitive, it becomes hard to explain to people that we’re not crazy, and perl *really* is cool, and it’s totally worth it once you get past… oh wait, where are you going?!? no, seriously, we don’t need CGI.pm any more!!! Damn it, lost another one.

      • barefootcoder says:

        Understood. The point, though, is that it isn’t the _constants_ that are the problem; it’s the _naming_. The only real problem we have in Perl (IMHO, natch) is that sometimes the wrong things snatch up all the good names, and then the good things come along later and have to settle for second best. ;->

  11. Ben Goldberg says:

    Perl5 uses one hash subscript operator, {}, which magically autoquotes the argument if it is a bareword, but doesn’t quote it otherwise. Too much magic! :)

    Note that this has nothing at all to do with constants: perl -e “$x{time} = 1; print keys %x” will produce “time”, not “1364154422” or whatever. For that matter, perl -e “print time => ”” also prints “time”, instead of seconds since the epoch.

    This is one reason why perl6 has two different hash subscript operators, namely which *always* autoquote the subscript, and {} which never *never* quotes the subscript.

  12. Grammar nitpick: “it’s” is short for “it is”, so your title says “use constant will surprise you with it is evil”, which doesn’t make sense. I suggest either “use constant will surprise you; it’s evil” or “use constant will surprise you with its evil”.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s