bakunin has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow monks!
I need an efficient way to determine which constants are given as arguments in a subroutine. Each constant will act as a switch later in some package. Here is some code:

package MyPackage; use constant { SCROLL_X = 1, SCROLL_Y=2, FLOW_X=3, FLOW_Y=4, ## and many more ... Let's say we have 20 constants }; ## this sub will tell us which constants are given, ## and maybe in some other part of the package other subs ## will kno +w what to turn on and off}; sub which_constants {#??? }

In "main" this subroutine is given some of the constants above:

MyPackage->which_constants(FLOW_X,SCROLL_Y);

In short, what are the approaches for sophisticated constant management in an OO environment!

Thank you!!!
Ogla Sungutay

20030714 Edit by Corion: Removed PRE tags

Replies are listed 'Best First'.
Re: managing constants created with constant.pm
by Zaxo (Archbishop) on Jul 14, 2003 at 08:35 UTC

    You are using the constant.pm pragmatic incorrectly, and constants don't do what you think they do.

    Correct syntax is,

    use constant SCROLL_X => 1; use constant SCROLL_Y => 2; use constant FLOW_X => 3; use constant FLOW_Y => 4;
    which produces constant subs of the form sub SCROLL_X () { 1;}. The prototype is important there, because it is a hint to the perl compiler that it may optimize away the sub call by replacing it with the constant value. There is no runtime reminant of the sub or its name.

    Update: As Abigail-II notes, recent constant.pm can take a hashref as argument. The syntax

    use canstant { SCROLL_X => 1, SCROLL_Y => 2, FLOW_X => 3, FLOW_Y => 4, };
    is fine if older versions need not be supported.

    After Compline,
    Zaxo

      The OP was using constants correctly. She's just using a modern version of Perl.

      Abigail

        In 5.8.1, $ perl -e'use constant { FOO = 1, BAR = 2}; print FOO,BAR' does not compile. With stringy commas, the combined form does work,

        $ perl -e'use constant { FOO => 1, BAR => 2}; print FOO,BAR' 12$
        '1' and '3' are not legal names for subs.

        After Compline,
        Zaxo

        Abigail, I'm male!! :))))))))
        And folks, please forget about the syntax!! Everything I code with constants work( as you all pointed out), and thanks :))))
        The question still remains unanswered! Any ideas?? I know how to solve the problem. I just have a feeling that it is not the perl way!
        Ogla
Re: managing constants created with constant.pm
by antirice (Priest) on Jul 14, 2003 at 09:21 UTC

    Well, you could do something along these lines:

    { my @constants = qw(scroll_x scroll_y flow_x flow_y); sub which_constants { my $self = shift; return undef unless ref($self); my %hashtest; @hashtest{map { $_ - 1 } grep(/^\d+$/ && 0<=$_ && $_<@constants,@_)} + = (); $self->{$constants[$_]} = exists $hashtest{$_} ? 1:0 for (0..$#const +ants); $self; } }

    Of course, I'm assuming that your object is a blessed hashref. Is it pretty? Nope. But it does work and...ummm...yep. Hope this helps.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

      Thanks antirice!
      Yes they're all blessed hashrefs. I'll work on it. For me it's very pretty.Any code containing this triplet "grep,map, hash slice" has the "coolness factor". :))))))
      Ogla
Re: managing constants created with constant.pm
by broquaint (Abbot) on Jul 14, 2003 at 09:43 UTC
    Cheeky, but effective
    sub UNIVERSAL::which_constants { my($class, @constants) = @_; return grep exists $constant::declared{"$class\::$_"}, @constants; }
    Now all your classes will have the which_consants class method which given a list of constant names returns the names which exist as constants in the given package. As you can see that's simply implemented by looking into the %constants::declared variable, so that's just one approach to the problem.
    HTH

    _________
    broquaint

      broquaint, I respect you very much. However, I was just wondering if you were aware that @constants will contain numbers and that you'll be checking whether or not a constant by that name exists...which it won't. Of course, you could declare the constants as X => "X" instead of X=>number to get it to work. I dunno. It's 4am and am being a bit dense I guess. :-/

      antirice    
      The first rule of Perl club is - use Perl
      The
      ith rule of Perl club is - follow rule i - 1 for i > 1

        that @constants will contain numbers and that you'll be checking whether or not a constant by that name exists...which it won't.
        Hmm, well maybe my function doesn't do what the OP requested (quite possible since it was written pre-1pm ;) but it will do what I intended - given a list of strings return if they exist in a given package e.g
        sub UNIVERSAL::which_constants { my($class, @constants) = @_; return grep exists $constant::declared{"$class\::$_"}, @constants; } use constant FOO => "a string"; use constant BAR => [ qw/ an array / ]; use constant BAZ => { qw/ a hash / }; print "constant exists - $_\n" for main->which_constants( qw/ ichi FOO bar BAZ one DEUX / ); __output__ constant exists - FOO constant exists - BAZ
        And if you want to go from constant values to constant names then check out chromatic's Devel::Constants module.
        HTH

        _________
        broquaint