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


in reply to C pre-processor in Perl

Could someone tell me why constant is preferable to #define in the following code?

Perhaps in the case you've shown, they're more or less equivalent, but as things grow more complex, the benefits of using constant instead start to show up.

Constants are scoped to Perl packages, not to a source file, which minimizes namespace conflicts:

package Potato; use constant tuber => 1; package Peach; use constant tuber => 0; package main; print Potato::tuber, Peach::tuber;

You can also define constant references to an array or hash:

use constant visited_urls => {}; ... unless ( visited_urls->{$my_url} ++ ) { ... }

Of course, there's tricks you can pull with pre-processor macros that go beyond what use constant can do, but for simple cases like the one you show, I'd encourage you to standardize on constant instead.

Replies are listed 'Best First'.
Re2: C pre-processor in Perl
by dragonchild (Archbishop) on Jul 28, 2003 at 19:32 UTC
    That constants are scoped to a Perl package vs. a source file seems to be a straw man for a few reasons:
    1. Good development techniques usually indicate that one package should exist in one file.
    2. For those cases where 2+ packages should co-exist in one file, I have often found that I want the same constants for all the packages within a file. But, I have to do things like Parent::SOME_CONSTANT instead of just SOME_CONSTANT, for that specific reason.
    Your two examples also seem to have contrivance problems.
    1. If I want to associate tuber-ness with Potatoes vs. Peaches, I would make it accessible via some method. So, instead of Potato::tuber, I would have Potato->is_tuber, or some such.
    2. Constant references to hashes/arrays don't seem to have a huge benefit. Why not just use %visited_urls instead? You gain scoping and the ability to treat it like any other variable. Instead, by making it a constant, I still don't have constant-ness and I'm requiring my maintainers to keep track of the fact that this name is supposedly a constant, though its contents are variable.
    I'm not attempting to shoot down all of your statements. I'm attempting to question what's behind them, so that you could potentially explain your thought processes. This is a completely new feature of Perl to me, and one that seems to have huge benefits. But, I am a little concerned with the fact that I've been programming in Perl for over 8 years and I've never heard of it. That raises a red flag to me and I wanted to know more about it.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      Good development techniques usually indicate that one package should exist in one file.

      Agreed, but what if I want to use those constants from a subclass, or in some other piece of code? More pre-processor trickery? Ick.

      The Perl pragma constants are accessible at runtime, and can be exposed to other modules in a normal Perl fashion.

      For those cases where 2+ packages should co-exist in one file, I have often found that I want the same constants for all the packages within a file. But, I have to do things like Parent::SOME_CONSTANT instead of just SOME_CONSTANT, for that specific reason.

      One technique you might find applicable is to define a constant and then export it to your other modules, the same way you would if they were spread out over multiple files:

      package MyFlags; use constant FooFlag => 42; use constant BarFlag => 23; use base 'Exporter'; BEGIN { @MyFlags::EXPORT_OK = qw( FooFlag BarFlag ); } BEGIN { $::INC{'MyFlags.pm'} ||= __FILE__; } package MyWidgetFactory; use MyFlags qw( FooFlag ); print FooFlag . "\n"; package MyFlyingMonkey; use MyFlags qw( FooFlag BarFlag ); print BarFlag . "\n";

      If I want to associate tuber-ness with Potatoes vs. Peaches, I would make it accessible via some method. So, instead of Potato::tuber, I would have Potato->is_tuber, or some such.

      Sure, by all means, go ahead and treat it as a method; after all, use constant is mostly just shorthand for making simple subroutines:

      package Potato; use constant tuber => 1; package main; print Potato->tuber;

      Constant references to hashes/arrays don't seem to have a huge benefit.

      Agreed, there's no breakthrough here -- just some syntactic sweetener... If your module's interface features a lot of public methods and only a couple of public package variables, it can be attractive to wrap those references in constant subs.

      This is a completely new feature of Perl to me, and one that seems to have huge benefits.

      Yup; both the CPP #defines and Perl constants are useful tools, each with their own ups and downs; I hope this post has clarified why, if given the choice, I'd typically use constant.