Need help with constants and package names.

Discussion in 'Perl Misc' started by Terry, Dec 12, 2004.

  1. Terry

    Terry Guest

    Hello all, I'm having trouble with packages and constants. What I'd
    like to have is a single .pm for all constants used by the application.
    The application will have other .pm files as well, and I'd like for them
    to have access to the constants as well. I thought the following would
    do what I want, but fails miserably:

    #### file: ./main
    #!/usr/bin/perl

    use warnings;
    use strict;

    use One::Two::Constants;
    use One::Two::Obj;

    print "Constant PI is: " , PI , "\n";
    my $obj = Obj->new();
    print "Object member PI is: " , $obj->{'pi'} , "\n";




    #### file ./One/Two/Constants.pm
    package One::Two::Constants;

    use constant { PI => 3.1415 };

    1;



    #### file ./One/Two/Obj.pm
    package One::Two::Obj;

    use warnings;
    use strict;

    use One::Two::Constants;

    sub new {
    my $class = shift;
    my $self = {
    some => 'thing' ,
    more => 'stuff' ,
    pi => PI
    };
    return bless $self , $class;
    }

    1;


    $ ./main
    Bareword "PI" not allowed while "strict subs" in use at One/Two/Obj.pm
    line 10.
    Compilation failed in require at ./main line 7.
    BEGIN failed--compilation aborted at ./main line 7.



    The only way I've been able to get this to run is by removing the
    package declaration from Constants.pm, changing the package declaration
    of Obj.pm to just 'package Obj', and by referring to 'PI' inside of
    Obj.pm as 'main::pI'. Clearly this is a poor approach.

    All I want is all constants kept in one place, able to be referred to
    from anywhere else. Any suggestions?

    As a side note, aren't package names supposed to be fully qualified?
    i.e, aren't .pm file supposed to begin with something like:

    package One::Two::Something;

    Importing with 'use' only seems to work when packages are declared with
    only their basename:

    package Something;

    Thank you for your help.

    -Terry
    Terry, Dec 12, 2004
    #1
    1. Advertising

  2. Terry

    John Bokma Guest

    John Bokma, Dec 12, 2004
    #2
    1. Advertising

  3. Terry wrote:

    > Hello all, I'm having trouble with packages and constants. What I'd
    > like to have is a single .pm for all constants used by the application.
    > The application will have other .pm files as well, and I'd like for them
    > to have access to the constants as well. I thought the following would
    > do what I want, but fails miserably:


    .... snip ...

    > #### file ./One/Two/Constants.pm
    > package One::Two::Constants;
    >
    > use constant { PI => 3.1415 };
    >
    > 1;


    Long answer, read:

    perldoc Exporter
    perldoc perlmod
    perldoc perlmodlib

    Short answer, to export symbols into the caller's package, inherit from
    Exporter and declare them in @EXPORT:

    package One::Two::Constants;

    use strict;
    use warnings;

    use Exporter;
    our @ISA = qw(Exporter);
    our @EXPORT = qw(PI);

    use constant PI => 3.1415;

    1;

    But *do* read the long answer. The code above is enough to get you
    started, but there's definitely a lot more to learn than this simple
    example shows.

    > As a side note, aren't package names supposed to be fully qualified?
    > i.e, aren't .pm file supposed to begin with something like:
    >
    > package One::Two::Something;


    That is correct.

    > Importing with 'use' only seems to work when packages are declared with
    > only their basename:
    >
    > package Something;


    No, use works just fine with nested module names. If it's not working
    for you, post a short (but complete) script that demonstrates the problem.

    sherm--

    --
    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
    Sherm Pendley, Dec 12, 2004
    #3
  4. Terry <> wrote in news:ca8pr0pkrtso5n6o2lanlnhscmc2mqlgk0@
    4ax.com:

    > Hello all, I'm having trouble with packages and constants.


    In addition to Sherm and John's excellent responses, let me just point
    out that you can save yourself a lot of trouble by using h2xs. While its
    official description states:

    DESCRIPTION
    *h2xs* builds a Perl extension from C header files. The extension
    will include functions which can be used to retrieve the value of
    any #define statement which was in the C header files.

    it can also be used to generate nice skeleton files for your modules.

    h2xs -AXn One::Two::Constants

    See

    perldoc h2xs

    for more information.

    Sinan

    --
    A. Sinan Unur
    d
    (remove '.invalid' and reverse each component for email address)
    A. Sinan Unur, Dec 12, 2004
    #4
  5. Terry

    Terry Guest

    On Sun, 12 Dec 2004 15:20:03 -0500, Sherm Pendley <>
    wrote:

    >Long answer, read:
    >
    >perldoc Exporter
    >perldoc perlmod
    >perldoc perlmodlib


    Thanks for the lead! After reading the Exporter perldoc I see my
    blunder.

    >Short answer, to export symbols into the caller's package, inherit from
    >Exporter and declare them in @EXPORT:
    >
    >package One::Two::Constants;
    >
    >use strict;
    >use warnings;
    >
    >use Exporter;
    >our @ISA = qw(Exporter);
    >our @EXPORT = qw(PI);
    >
    >use constant PI => 3.1415;
    >
    >1;



    Something I didn't find in the perldoc was how to export a hash using
    the 'use constant' pragma. The examples seemed to be geared toward
    single imports as in your example. The reason I'm using 'use export'
    with a hash ref is to import multiple constants (I'll have at least
    fifty by the time I'm done). ie:

    use constant {
    one => 1 ,
    two => 2 ,
    # ...
    };

    How then to pass this list to @EXPORT ? I tried assigning the hash ref
    to a scalar first and assigning its keys into @ISA , but you probably
    already know that didn't work ;) Any suggestions?



    >> As a side note, aren't package names supposed to be fully qualified?
    >> i.e, aren't .pm file supposed to begin with something like:
    >>
    >> package One::Two::Something;

    >
    >That is correct.
    >
    >> Importing with 'use' only seems to work when packages are declared with
    >> only their basename:
    >>
    >> package Something;

    >
    >No, use works just fine with nested module names. If it's not working
    >for you, post a short (but complete) script that demonstrates the problem.
    >


    The Obj.pm file in my last post demonstrates the problem:


    ##### file: ./One/Two/Obj.pm
    package One::Two::Obj;

    use warnings;
    use strict;

    use One::Two::Constants;

    sub new {
    my $class = shift;
    my $self = {
    some => 'thing' ,
    more => 'stuff' ,
    pi => PI
    };
    return bless $self , $class;
    }

    1;

    ###### file ./main
    #!/usr/bin/perl

    use warnings;
    use strict;

    use One::Two::Constants;
    use One::Two::Obj;

    my $obj = Obj->new();



    $ ./main
    Can't locate object method "new" via package "Obj" (perhaps you forgot
    to load "Obj"?) at ./main line 10.

    If I change the package declaration in Obj.pm from 'One::Two::Obj' to
    just 'Obj' it works fine. I also tried exporting 'new' from Obj.pm as
    in your example above to no avail.

    >sherm--


    Thanks again for your help Sherm!
    Terry, Dec 12, 2004
    #5
  6. On 2004-12-12, A. Sinan Unur scribbled these
    curious markings:
    > In addition to Sherm and John's excellent responses, let me just point
    > out that you can save yourself a lot of trouble by using h2xs. While its
    > official description states:

    [...]
    > See
    >
    > perldoc h2xs


    In further addition, I'd like to suggest Module::Starter (and its
    command-line frontend, module-starter) as a modern alternative /
    complement to h2xs. It presents a friendlier interface to module
    skeleton creation, and isn't historically (read: confusingly, for the
    new user anyway) named.

    You can find M::S on your local CPAN mirror.

    Best Regards,
    Christopher Nehren
    --
    I abhor a system designed for the "user", if that word is a coded
    pejorative meaning "stupid and unsophisticated". -- Ken Thompson
    If you ask the wrong questions, you get answers like "42" and "God".
    Unix is user friendly. However, it isn't idiot friendly.
    Christopher Nehren, Dec 12, 2004
    #6
  7. Christopher Nehren <> wrote in
    news::

    > In further addition, I'd like to suggest Module::Starter (and its
    > command-line frontend, module-starter) as a modern alternative /
    > complement to h2xs.


    I did not know about this module. Thanks very much.

    Sinan.

    --
    A. Sinan Unur
    d
    (remove '.invalid' and reverse each component for email address)
    A. Sinan Unur, Dec 12, 2004
    #7
  8. Terry wrote:

    > Something I didn't find in the perldoc was how to export a hash using
    > the 'use constant' pragma. The examples seemed to be geared toward
    > single imports as in your example. The reason I'm using 'use export'
    > with a hash ref is to import multiple constants (I'll have at least
    > fifty by the time I'm done). ie:
    >
    > use constant {
    > one => 1 ,
    > two => 2 ,
    > # ...
    > };
    >
    > How then to pass this list to @EXPORT ? I tried assigning the hash ref
    > to a scalar first and assigning its keys into @ISA , but you probably
    > already know that didn't work ;) Any suggestions?


    I haven't found a way to do that either - and believe me I've tried. In
    my CamelBones project I have one file with over a hundred constants -
    each one appears twice, once to define its value and once in @EXPORT.

    > The Obj.pm file in my last post demonstrates the problem:
    >
    > ##### file: ./One/Two/Obj.pm
    > package One::Two::Obj;
    >
    > use warnings;
    > use strict;
    >
    > use One::Two::Constants;
    >
    > sub new {


    .... snip ...

    > ###### file ./main
    > #!/usr/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > use One::Two::Constants;
    > use One::Two::Obj;
    >
    > my $obj = Obj->new();
    >
    >
    > $ ./main
    > Can't locate object method "new" via package "Obj" (perhaps you forgot
    > to load "Obj"?) at ./main line 10.


    To call a class method like new(), you need to specify the full class
    name, not just the last component of it:

    my $obj = One::Two::Obj->new();

    Objects know what package they belong to though, so instance methods can
    be called with the name of the method alone:

    $obj->do_something();

    > If I change the package declaration in Obj.pm from 'One::Two::Obj' to
    > just 'Obj' it works fine.


    In that case, you're not using Exporter in One::Two::Obj. If you were,
    it wouldn't work as expected because the file name doesn't match the
    package name.

    use One::Two::Obj;

    is roughly equivalent to

    BEGIN {
    require "One/Two/Obj.pm";
    One::Two::Obj::import();
    }

    But if the code in One/Two/Obj.pm is actually in package Obj, there
    would be no One::Two::Obj::import() to call. So the symbols in the
    module wouldn't be correctly imported into the calling package.

    > I also tried exporting 'new' from Obj.pm as


    You only need to export non-oo functions. Class methods are normally
    called using the fully-qualified class name as above. Instance methods
    are called via an object reference, and the class of the object is used
    to determine the package to find the method in.

    sherm--

    --
    Cocoa programming in Perl: http://camelbones.sourceforge.net
    Hire me! My resume: http://www.dot-app.org
    Sherm Pendley, Dec 12, 2004
    #8
  9. Terry

    Terry Guest

    On Sun, 12 Dec 2004 17:24:16 -0500, Sherm Pendley <>
    wrote:

    >I haven't found a way to do that either - and believe me I've tried. In
    >my CamelBones project I have one file with over a hundred constants -
    >each one appears twice, once to define its value and once in @EXPORT.


    Thanks anyway. I looked at your CamelBones project too - very
    interesting!

    >To call a class method like new(), you need to specify the full class
    >name, not just the last component of it:
    >
    >my $obj = One::Two::Obj->new();


    Ah, got it. I was expecting it to be Java-ish, where after the package
    is imported, it can be instantiated via its class name only.

    Thanks again for the help Sherm.

    -Terry
    Terry, Dec 13, 2004
    #9
  10. Terry

    Terry Guest

    On 12 Dec 2004 21:40:32 GMT, "A. Sinan Unur" <>
    wrote:

    >Christopher Nehren <> wrote in
    >news::
    >
    >> In further addition, I'd like to suggest Module::Starter (and its
    >> command-line frontend, module-starter) as a modern alternative /
    >> complement to h2xs.

    >
    >I did not know about this module. Thanks very much.
    >
    >Sinan.


    Thanks for the help on this thread! I'm working with a refactor of some
    existing code, but I'll remember this the next time I need to create a
    module.

    -Terry
    Terry, Dec 13, 2004
    #10
  11. Sherm Pendley wrote:

    > Terry wrote:
    >
    >> Something I didn't find in the perldoc was how to export a hash using
    >> the 'use constant' pragma. The examples seemed to be geared toward
    >> single imports as in your example. The reason I'm using 'use export'
    >> with a hash ref is to import multiple constants (I'll have at least
    >> fifty by the time I'm done). ie:
    >>
    >> use constant {
    >> one => 1 ,
    >> two => 2 ,
    >> # ...
    >> };
    >>
    >> How then to pass this list to @EXPORT ? I tried assigning the hash ref
    >> to a scalar first and assigning its keys into @ISA


    Surely you mean @EXPORT?

    >> , but you probably already know that didn't work ;)


    It works just fine if you pay proper attension to run-time v.
    compile-time issues.

    > I haven't found a way to do that either - and believe me I've tried.


    BEGIN {
    my %constants = (
    one => 1 ,
    two => 2 ,
    # ...
    );
    require constants;
    import constants %constants;
    push @EXPORT => keys %constants;
    }
    Brian McCauley, Dec 13, 2004
    #11
  12. Terry <> writes:
    > Hello all, I'm having trouble with packages and constants. What I'd
    > like to have is a single .pm for all constants used by the application.


    Others have commented on how, and why (and why not), so I'll just add
    my two cents on the wisdom of doing so:

    On clpm, we tell everybody to 'use warnings;' and 'use strict;'. Why?
    Because, among other things, they force you to declare your variables,
    so you can catch when you typo writing one and also so you can trace
    the life of your variable more easily. When you import a variable
    (or a constant), you're effectively circumventing at least one of
    those benefits.

    Admittedly, it's worse with variables, where you're potentially
    subject to action-at-a-distance when some random code out there
    somewhere modifies a variable you didn't know it was modifying, but
    even with constants, unless you explicitly import them all, it's very
    easy to forget where it's defined and why, if you're in the habit of
    exporting such things by default. (And for my next trick, a run-on
    sentence the length of War and Peace!)

    Just a thought.

    -=Eric
    --
    Come to think of it, there are already a million monkeys on a million
    typewriters, and Usenet is NOTHING like Shakespeare.
    -- Blair Houghton.
    Eric Schwartz, Dec 14, 2004
    #12
  13. Terry

    Ben Morrow Guest

    Quoth Brian McCauley <>:
    > Sherm Pendley wrote:
    > > Terry wrote:
    > >
    > >> Something I didn't find in the perldoc was how to export a hash using
    > >> the 'use constant' pragma.

    <snip>
    >
    > It works just fine if you pay proper attension to run-time v.
    > compile-time issues.
    >
    > > I haven't found a way to do that either - and believe me I've tried.

    >
    > BEGIN {
    > my %constants = (
    > one => 1 ,
    > two => 2 ,
    > # ...
    > );
    > require constants;
    > import constants %constants;
    > push @EXPORT => keys %constants;
    > }


    That BEGIN is unnecessary if there is no other code in the file: the
    require is happening at BEGIN time anyway, and before import is called.

    If there *is* other code in the file, it won't have access to the
    constants.

    Ben

    --
    don't get my sympathy hanging out the 15th floor. you've changed the locks 3
    times, he still comes reeling though the door, and soon he'll get to you, teach
    you how to get to purest hell. you do it to yourself and that's what really
    hurts is you do it to yourself just you, you and noone else **
    Ben Morrow, Dec 17, 2004
    #13
  14. Ben Morrow wrote:
    > Quoth Brian McCauley <>:
    >
    >>Sherm Pendley wrote:
    >>
    >>>Terry wrote:
    >>>
    >>>
    >>>>Something I didn't find in the perldoc was how to export a hash using
    >>>>the 'use constant' pragma.

    >
    > <snip>
    >
    >>It works just fine if you pay proper attension to run-time v.
    >>compile-time issues.
    >>
    >>
    >>>I haven't found a way to do that either - and believe me I've tried.

    >>
    >>BEGIN {
    >> my %constants = (
    >> one => 1 ,
    >> two => 2 ,
    >> # ...
    >> );
    >> require constants;
    >> import constants %constants;
    >> push @EXPORT => keys %constants;
    >>}

    >
    >
    > That BEGIN is unnecessary if there is no other code in the file: the
    > require is happening at BEGIN time anyway, and before import is called.
    >
    > If there *is* other code in the file, it won't have access to the
    > constants.


    How do you figure that?

    There were several mistakes in my code but that wasn't one of them. The
    two lines...

    require constants;
    import constants %constants;

    ....should have read...

    require constant;
    import constant $_ => $constants{$_} for keys %constants;

    ....and then the code beyond the BEGIN block _can_ access the the constants.
    Brian McCauley, Dec 19, 2004
    #14
    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. fBechmann
    Replies:
    0
    Views:
    399
    fBechmann
    Jun 10, 2004
  2. wanwan
    Replies:
    3
    Views:
    429
    Alex Martelli
    Oct 14, 2005
  3. Agoston Bejo

    Retrieve package constants

    Agoston Bejo, Sep 1, 2004, in forum: ASP General
    Replies:
    0
    Views:
    110
    Agoston Bejo
    Sep 1, 2004
  4. ed
    Replies:
    3
    Views:
    127
    Martien Verbruggen
    Jun 26, 2003
  5. Replies:
    15
    Views:
    204
    comp.llang.perl.moderated
    May 14, 2008
Loading...

Share This Page