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

Hi

for performance reasonsı I have to hold data in an array instead of a hash, but I don't wanna obfuscate my code with numerical indices.

IIRC there is a deprecated approach to define hash-like arrays for this reason (actually I can't find it in the 5.10 docs anymore)

The best solution I came up till now is using constants in a dedicated package to hold the indices:

my @arr=("jesus","heaven"); { package t; sub NAME () {0}; sub ADDRESS () {1}; print $arr[NAME],$arr[ADDRESS] } print $arr[t::NAME],$arr[t::ADDRESS];

Such that the indices will be expanded at compile time.

> perl -MO=Deparse /tmp/tst.pl sub t::NAME () { 0 } sub t::ADDRESS () { 1 } my(@arr) = ('jesus', 'heaven'); { package t; print $arr[0], $arr[1]; } print $arr[0], $arr[1]; /tmp/tst.pl syntax OK

Any other suggestions???

Cheers Rolf

UPDATE: hmm I could use ' instead of :: to shorten the notation.

1) a deeply branching recursive function.

Replies are listed 'Best First'.
Re: Named array indices
by almut (Canon) on Aug 05, 2010 at 17:24 UTC
    IIRC there is a deprecated approach to define hash-like arrays for this reason (actually I can't find it in the 5.10 docs anymore)

    They were called pseudo hashes, but that functionality has been removed in 5.9 without any real replacement (unfortunately, IMHO).  (Yes, there's use fields which now uses restricted hashes internally, but I don't think that'll help with your requirement...)

      They were called pseudo hashes,

      Ahhh ... excactly!

      I was googling with combinations with "Array" not "Hashes"! :)

      Cheers Rolf

Re: Named array indices
by Old_Gray_Bear (Bishop) on Aug 05, 2010 at 17:19 UTC
    I've used the constant pragma to address this problem. I believe that it actually resolves at Compile time and get away from repeated subroutine calls at Run time. (But I may be remembering wrong, the library in my local Coffee shop is woefully lacking in Perl material. Maybe I ought to fix that....)
    #! /usr/local/bin/perl use strict; use warnings; use constant AAA=>1; use constant BBB=>0; my @this_array; $this_array(AAA) = 'Scrumtidlyumptions'; $this_array(BBB) = 'Cupcakes taste'; print(join(' ',@this_array), "\n");
    Coded but not run.

    ----
    I Go Back to Sleep, Now.

    OGB

      AFAIK this is basically the same approach.

      The constant pragma just produces the inlinedı subs I used.

      IMHO the namespaces of constants and subs collide.

      Cheers Rolf

      1) like sub AAA(){1} , i.e. empty prototype and ending with value evaluable at compile-time.

        Constants are a bit more memory efficient and easier to read.
Re: Named array indices (packages)
by tye (Sage) on Aug 06, 2010 at 06:09 UTC
    package Your::Class; our $VERSION= 1.001_001; package Your::Class::_Implementation; BEGIN { require constant; my $offset= 0; for my $member ( qw< _NAME _ADDRESS _PHONE ... > ) { constant->import( $member, $offset++ ); } } sub Your::Class::new { ... $self->[_NAME]= ...; }

    If you don't like writing "sub Your::Class::new" instead of "sub new", then you can instead do something like:

    ... package Your::CLass::_Implementation; ... sub new { ... } ... package Your::Class; BEGIN { require Exporter; for my $method ( qw< new ... > ) { Exporter::import( 'Your::Class:_Implementation', $method ); } }

    This also allows you to separate your class methods fom your ojects methods, just FYI.

    It isn't difficult to abstract out these tools to make them look prettier.

    Note that a C' prefix is a horrible idea:

    package Your::Class; ... sub C'Name() { 0; } ... package Something::Completely::Different; ... sub C'Index() { 0; } sub C'Name() { 1; } # Boom! ...

    - tye        

      Note that a C' prefix is a horrible idea:
      You probably missed (as did I) the second paragraph in perlmod:
      The old package delimiter was a single quote, but double colon is now the preferred delimiter...

        Uh, no. A C:: prefix is equivalently horrible (of course). That was the point. Perhaps you missed the "Boom!" comment? Or did you not understand the significance of it?

        - tye        

      Note that a C' prefix is a horrible idea:

      Well the problem is the same for double colon syntax.

      I would need relative package paths but can't achieve them easily.

      I couldn't even make something like $arr[__PACKAGE__::C::Index] or $arr[__PACKAGE__.'::C::Index'] expand correctly at compile time.

      So BUK has a point to use underscore prefixes!

      Anyway my intention to use a package for the array indices was to avoid polluting the package namespace with constants which should only be associated and encapsulated to special datastructures.

      I'm not completely understanding the code you're showing, looks like your globally importing the constants into the package and facilitating the initialization of the index-values. (As a side node there is constant::lexical2 on CPAN)

      Thanx!

      Cheers Rolf

      UPDATE: did clarification of two phrases.

Re: Named array indices
by BrowserUk (Patriarch) on Aug 05, 2010 at 17:34 UTC
    IMHO the namespaces of constants and subs collide.

    Do you use many ALL_UPPER subnames in your code?

    Alternatively, just use a prefix: use constant C_NAME => 0;


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I was just making clear that both use the same name space.

      > Alternatively, just use a prefix: use constant C_NAME => 0;

      In big projects I'd rather prefer a dedicated package instead of a prefix, in small ones collisions are unlikely.

      Using the C'NAME syntax mightı make the notation even shorter and help giving a visual hint.

      Cheers Rolf

      1) at least I didn't get any complaints when compiling with strict and warnings.

        In big projects I'd rather prefer a dedicated package instead of a prefix

        Why? C_... and C'... give exactly the same level of segregation.

        I think that you just like the cuteness of the latter. (So do I.) But how many of those that follow you will be completely confused, by that ancient syntax?


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Named array indices
by lmgjerstad (Initiate) on Aug 06, 2010 at 11:00 UTC

    Depending on your situation, you may also find Data::Alias to provide a good alternative.

    use Data::Alias; my @array = ( [1,2], [3,4], [5,6], ); foreach my $list (@array) { alias my ($first, $second) = @{$list}; print $first, $second; }

    Any performance hit will be trivial, and you'll get a performance boost over an array if you access the values more than once.

      Thanks, but in my special case I would need to intialize the alias each time I'm accessing the data. So IMHO the overhead would kill the speed-gain...

      Cheers Rolf

Re: Named array indices (workaround)
by LanX (Saint) on Aug 06, 2010 at 14:06 UTC
    Hi

    I found a simple solution in my special case now by turning my array inside out!

    Thats means instead of writing $arrays[$level][NAME] I will use $name[$level] in my code.

    This has the special benefit that I can restrict the scope of my @name, which I can't easily do with a constant like NAME.

    Cheers Rolf