use constant SUBJECT => 'Defining Constants'; # was: !0

Andy Wardley abw at wardley.org
Fri Feb 13 13:05:38 GMT 2009


Peter Corlett wrote:
> Like comments, constant names should expand on the meaning of the code 
> rather than just repeat it, and should mean the same thing in each 
> place. 

I totally agree that constant names shouldn't obfuscate their values,
and they should always have the same, sane value.  However, I don't
agree with your first point.

In recent years I've found myself writing more and more constants that
simply repeat the word itself.  The Badger::Constants module defines a
bunch of these that I use all the time.

For example:

    use Badger::Constants 'ARRAY HASH';

    if (ref $foo eq ARRAY) {
        ...
    }
    elsif (ref $foo eq HASH) {
        ...
    }

Here ARRAY is a constant definition of 'ARRAY' and likewise for HASH.

In fact, I use this stating-the-bleeding-obvious approach to constants so
much that I added a handy hook to Badger::Class for defining them.

     use Badger::Class
         words => 'yes no maybe';

     if ($response eq yes) {
        ...
     }
     elsif ($response eq no) {
        ...
     }

The benefits to me are:

   1) If I misytpe the word then Perl tells me at compile time.

   2) It saves on typing (and reading) the two extra quote characters.
      This adds up over time.

   3) My syntax highlighter makes it go black (boring) instead of the
      blue (interesting) colour it uses for strings.  This reduces the
      cognitive load when skimming the code. Skimmable code++

The downside is that all constants are effectively polluting your package
namespace.  In Perl, constants are subroutines are methods, so you can call
any constant subroutine as a class or object method.  However, this can also
be used to great effect for things like defining default configuration values
for a module:

     package Hello;
     use constant MESSAGE => 'Hello World';

     sub new {
          my $class   = shift;
          my $message = shift || $class->MESSAGE;    # looky here
          bless { message => $message }, $class;
     }

You can then sub-class it like so:

     package Bonjour;
     use base 'Hello';
     use constant MESSAGE => 'Bonjour le Monde';

By resolving the MESSAGE constant against $class (or an $object of $class)
in the new() method, we get the subclass definition of MESSAGE instead of the
base class one.  Neat, eh?

BTW, my favourite constant definition of all time is 'PKG' which is defined to
be '::'.  For example, the Badger::Class words() method (which defines those
same-named constants in the earlier example) does this:

    *{ $pkg.PKG.$word } = sub() { $word };

Instead of the harder-to-type:

    *{ $pkg.'::'.$word } = sub() { $word };

Or the even-harder-to-type, gnarlier-to-read, and running-more-slowishly
alternative:

    *{"${pkg}::${word}"} = sub() { $word };

Ah!  Perfect timing... my database has just finished importing... back to
work...

Tune in next week for more "Constant Definitions I Have Known and Loved". :-)

A



More information about the london.pm mailing list