Handling constants in Perl?

Discussion in 'Perl Misc' started by newsbot@cox.net, Apr 19, 2005.

  1. Guest

    First my disclaimer... 5 Years of Perl and I've never really needed to
    do what I am asking here (mainly because of how Perl works so well
    without it, I guess), but I need to do it now, and I'm a little
    surprised that it doesn't work the way I thought it would.

    I want to be able to hold, in one place, a file/module of constants
    that I can use in any other module in a project. Kind of like header
    files (.h) in C:

    #define FOO "bar"

    Then I include that .h file in all .c source files. So in Perl, I did
    this:

    === TestK.pm ===

    use constant TEST1 => 'Test1';
    use constant TEST2 => 'FooBar';

    1;

    === TestMod.pm ===

    #!/usr/bin/perl
    $|++;

    use strict;
    use warnings qw( all );

    use TestK;

    sub Test {

    print __PACKAGE__ . ": TEST1 = " . TEST1 . "\n";
    print __PACKAGE__ . ": TEST2 = " . TEST2 . "\n";

    }

    1;

    === test.pl ===

    #!/usr/bin/perl
    $|++;

    use strict;
    use warnings qw( all );

    use TestK;
    use TestMod;

    TestMod::Test();

    print __PACKAGE__ . ": TEST1 = " . TEST1 . "\n";
    print __PACKAGE__ . ": TEST2 = " . TEST2 . "\n";

    __END__

    I *don't* get what I expect here. Instead, I get:

    Bareword "TEST1" not allowed while "strict subs" in use at test.pl line
    12.
    Bareword "TEST2" not allowed while "strict subs" in use at test.pl line
    13.

    It's like I can't "use TestK" in both test.pl and TestMod.pm. If I
    comment out the "use TestMod;" and the TestMod::Test() call in test.pl,
    the print statments in test.pl are fine. If I comment out the print
    statements in test.pl and the "use TestK;" in test.pl, then the call to
    TestMod::Test() in test.pl is fine. But I can't do both.

    Documentation on "use constants" says that constants are package
    scoped. But without providing a package name for the constants in
    TestK.pm, I would expect the constants to be scoped to each package
    they were used in, so I would get:

    main::TEST1
    main::TEST2
    TestMod::TEST1
    TestMod::TEST2

    Obviously, this is NOT the case. And again, I don't recall ever
    needing to do this, so I'm a little amazed. I don't recall (nor find
    on Google in c.l.p.m) any real discussion of using constants in
    multiple packages. (I think mainly because use of "constants" in Perl
    as they are in C isn't in high use.)

    Can anyone shed light on the above?

    Thanks!
    -ceo
    , Apr 19, 2005
    #1
    1. Advertising

  2. wrote:
    > First my disclaimer... 5 Years of Perl and I've never really needed to
    > do what I am asking here (mainly because of how Perl works so well
    > without it, I guess), but I need to do it now, and I'm a little
    > surprised that it doesn't work the way I thought it would.
    >
    > I want to be able to hold, in one place, a file/module of constants
    > that I can use in any other module in a project. Kind of like header
    > files (.h) in C:
    >
    > #define FOO "bar"
    >
    > Then I include that .h file in all .c source files. So in Perl, I did
    > this:
    >
    > === TestK.pm ===
    >
    > use constant TEST1 => 'Test1';
    > use constant TEST2 => 'FooBar';
    >
    > 1;

    <snip>
    There has just been a question on this but:

    perldoc Exporter


    > Obviously, this is NOT the case. And again, I don't recall ever
    > needing to do this, so I'm a little amazed. I don't recall (nor find
    > on Google in c.l.p.m) any real discussion of using constants in
    > multiple packages. (I think mainly because use of "constants" in Perl
    > as they are in C isn't in high use.)

    bob 989 $ grep -lr "use constant" /usr/local/lib/perl5 | wc
    121 121 7298
    bob 990 $ grep -lr "Exporter" /usr/local/lib/perl5 | wc
    340 340 17656

    (though constants can be defined by other means)

    Both "use constants" and the Exporter are used quite extensively in CPAN
    and the core modules..

    regards,

    Mark
    Mark Clements, Apr 19, 2005
    #2
    1. Advertising

  3. Guest

    Putting the constants in a package and exporting them seems to work
    fine. I just didn't expect this and would still like to know if anyone
    can shed light on why it doesn't work the way I originally expected.

    Perl Cookbook gives a somewhat brief but informative rundown on
    constants and says that constants are scoped to the package in which
    they are created. Which to me means it should work the way I
    originally expected this to work.

    Anyway...

    === TestK.pm ===

    package TestK;

    use base qw( Exporter );
    @EXPORT = qw( TEST1 TEST2 );

    use constant TEST1 => 'Test1';
    use constant TEST2 => 'FooBar';

    1;
    __END__

    ....seems to work. Now test.pl runs as I expected it to run:

    $ test.pl
    TestMod: TEST1 = Test1
    TestMod: TEST2 = Test2
    TestMod: TEST3 = Test3
    main: TEST1 = Test1
    main: TEST2 = Test2
    main: TEST3 = Test3

    Thanks!
    -ceo
    , Apr 19, 2005
    #3
  4. Guest

    I just replied with the same as this was being posted. So this seems
    to work. But my original question still stands however. Why doesn't
    it work the way the documentation on "use constant" says that it
    would/should work? If I use a module with no package name, then the
    routines and variables in the module should be scoped to the current
    package...

    -ceo
    , Apr 19, 2005
    #4
  5. wrote:
    > I just replied with the same as this was being posted. So this seems
    > to work. But my original question still stands however. Why doesn't
    > it work the way the documentation on "use constant" says that it
    > would/should work? If I use a module with no package name, then the
    > routines and variables in the module should be scoped to the current
    > package...


    OK - I see what you mean now.

    bob 548 $ cat TestConstant.pm
    use constant TT => 1;
    use constant UU => 2;

    1;
    bob 549 $ cat test1.pl
    use strict;
    use warnings;

    use TestConstant;

    print UU."\n";
    bob 550 $ perl test1.pl
    2


    TestConstant has no package defined, so main is assumed, so TT and UU
    become part of the main package.


    When I run your code (from original post) I get:

    Undefined subroutine &TestMod::Test called at test1.pl line 10.

    TestMod.pm has been included, but doesn't define the package TestMod, so
    therefore the subroutine it defines appears in the main package.

    If I correct this (ie call main::Test) the result is:

    main: TEST1 = Test1
    main: TEST2 = FooBar
    main: TEST1 = Test1
    main: TEST2 = FooBar

    bob 631 $ perl -v

    This is perl, v5.8.2 built for sun4-solaris

    Which perl are you using?

    Mark
    Mark Clements, Apr 19, 2005
    #5
  6. I think the reason your program fails is in the nature of use
    statement. According to perlfunc use is actually BEGIN { require
    Module; import Module LIST; }. This is my explanation of what is
    happening without Exporter module:
    - when you use your constant module first time (use TestK), it's
    really included
    - no importing going with step
    - when you use your constant module second time (in main program), it
    is not included, because perl does not include files second time (see
    %INC hash for list of included files)
    - no importing going with step too
    - so compiler does not see your constants

    If you are using Exporter:
    - when you use your constant module first time (use TestK), it's
    really included
    - importing of names
    - when you use your constant module second time (in main program), it
    is not included
    - but importing is going
    - and the constants are available

    Conclusion: you'd better use Exporter, to get full module

    P.S. I actually fail on this very tricky issue, but in more complex
    situation :) Sorry for my bad English.
    Ivan Nevostruev, Apr 20, 2005
    #6
  7. Guest

    Ok, this is what I get for retyping and not cutting and pasting... A
    cardinal rule broken... (How many FAQs does it take?) Sorry.

    TestMod.pm should have read:

    === TestK.pm ===

    package TestMod;

    use strict;
    use warnings qw( all );

    use TestK;

    sub Test {

    print __PACKAGE__ . ": TEST1 = " . TEST1 . "\n";
    print __PACKAGE__ . ": TEST2 = " . TEST2 . "\n";

    }

    1;

    __END__

    (Cut and pasted this time.)

    Which is how I ran it. THEN it gave me the error I originally
    described.

    I am using ActiveState Perl for Windows v5.8.4.

    -ceo
    , Apr 21, 2005
    #7
  8. Well, i run your script and get the following errors:
    > Bareword "TEST1" not allowed while "strict subs" in use at TestMod.pm

    line 7.
    > Bareword "TEST2" not allowed while "strict subs" in use at TestMod.pm

    line 8.
    > Compilation failed in require at test.pl line 8.
    > BEGIN failed--compilation aborted at test.pl line 8.

    They occur because line "use TestK;" is before line "use TestMod;" in
    test.pl. So perl includes 'TestK.pm' into test.pl. And when it parses
    'TestMod.pm', it does not include 'TestK.pm', because with file in
    already included.

    And if you just change line order to "use TestMod;use TestK;" in
    test.pl, the following errors occur:
    > Bareword "TEST1" not allowed while "strict subs" in use at test.pl

    line 12.
    > Bareword "TEST2" not allowed while "strict subs" in use at test.pl

    line 13.
    > Execution of test.pl aborted due to compilation errors.


    To prevent those errors, you need to write complete module with
    Exporter. Including of 'TestK.pm' file occurs only once (just as it was
    before), but 'import' method will be called twice, and your constants
    will be imported into all namespaces you need.
    Ivan Nevostruev, Apr 22, 2005
    #8
  9. Anno Siegel Guest

    Ivan Nevostruev <> wrote in comp.lang.perl.misc:
    > Well, i run your script and get the following errors:
    > > Bareword "TEST1" not allowed while "strict subs" in use at TestMod.pm

    > line 7.
    > > Bareword "TEST2" not allowed while "strict subs" in use at TestMod.pm

    > line 8.
    > > Compilation failed in require at test.pl line 8.
    > > BEGIN failed--compilation aborted at test.pl line 8.

    > They occur because line "use TestK;" is before line "use TestMod;" in
    > test.pl. So perl includes 'TestK.pm' into test.pl. And when it parses
    > 'TestMod.pm', it does not include 'TestK.pm', because with file in
    > already included.
    >
    > And if you just change line order to "use TestMod;use TestK;" in
    > test.pl, the following errors occur:
    > > Bareword "TEST1" not allowed while "strict subs" in use at test.pl

    > line 12.
    > > Bareword "TEST2" not allowed while "strict subs" in use at test.pl

    > line 13.
    > > Execution of test.pl aborted due to compilation errors.


    No. If the module TestMod uses TestK itself (and the modules are
    otherwise written correctly), "use TestK" after "use TestMod" has
    no effect.

    > To prevent those errors, you need to write complete module with
    > Exporter. Including of 'TestK.pm' file occurs only once (just as it was
    > before), but 'import' method will be called twice, and your constants
    > will be imported into all namespaces you need.


    Not really. All it takes is to remove the spurious "use TestK" from
    the main program. That is taken care of by TestMod, as it should be.
    Then the arrangement works as the OP intended.

    Another question is whether it's wise to have a module whose effect
    depends on which package gets hold of it first. (The first package gets
    the constants, others get nothing.) We have seen right in this thread
    that this behavior is confusing. Much better to put the constants in
    their own Exporting package and let clients import what they need.

    Anno
    Anno Siegel, Apr 23, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mark Tarver
    Replies:
    22
    Views:
    1,275
    J Kenneth King
    Apr 26, 2009
  2. Peter
    Replies:
    34
    Views:
    1,913
    James Kanze
    Oct 17, 2009
  3. Iñaki Baz Castillo
    Replies:
    1
    Views:
    174
    Iñaki Baz Castillo
    Apr 15, 2008
  4. Hallvard Breien Furuseth

    Module for common perl/shell/python constants

    Hallvard Breien Furuseth, Nov 16, 2012, in forum: Perl Misc
    Replies:
    6
    Views:
    301
    C.DeRykus
    Nov 18, 2012
  5. Ivan Shmakov
    Replies:
    15
    Views:
    240
    Peter J. Holzer
    Jul 7, 2013
Loading...

Share This Page