Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

  (email not shown publicly)
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Friday March 03, 2006
06:06 PM

Find the bug!

[ #28868 ]

I had to add a new feature to my Array::AsHash module. Basically, you might need to get keys and values at particular array indices (think "a list of pairs"), so I needed to allow this:

my $key  = $array->key_at(2);
my @keys = $array->key_at(0, 3, -1);
my $keys = $array->key_at(0, 3, -1); # aref

So I wrote code like this (I did something similar for values):

sub key_at {
    my $self  = CORE::shift;
    my $ident = ident $self;
    my @keys;
    foreach my $index (@_) {
        $index *= 2;
        CORE::push @keys => $array_for{$ident}[$index];
    return wantarray ? @keys
        : 1 == @_    ? $keys[0]
        :              \@keys;

See the bug? There are a couple of subtle issues here, but one of them is a real whopper. When you see it, you'll know.

FYI: The CORE:: stuff is there because I have methods named shift and push. ident is from Class::Std.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
More | Login | Reply
Loading... please wait.
  • Well, this is a stab in the dark, but when I see -1 being used in a fetch-from-array context, I tend to assume it's counting from the end of the array, not being treated directly as an index. Other than that, you aren't checking whether you're called on a reference or statically, which leads me to think that "ident $self" might not always return what you expect it to return.


    • Trust me. Once you see the bug, it's a forehead slapper -- if you've encountered this behavior before. It's something that folks often miss because it occurs so rarely, but it's a natural consequence of how Perl behaves.

  • (Rot-13'ed)
    Lbh'er zbqvslvat gur inyhrf bs gur cnenzrgre yvfg juvpu ner nyvnfrq gb gur inyhrf bs gur inevnoyrf va gur pnyyre'f fpbcr, gurersber zbqvslvat gur pnyyre'f fpbcr, be va guvf pnfr, "ernq-bayl inyhrf".

    Of course, your tests should have found this instantly, if you used something like the examples you have there, as it throws up an immediate error.

    Why does Perl do this? It's bitten me in the ass a few times, and I can't seriously imagine using it deliberately in code to be maintained.
    • Right in one! Fortunately, the fix is trivial, but it's strange to see if folks don't know what's going on, so I document it.

    • Why does Perl do this? It's bitten me in the ass a few times, and I can't seriously imagine using it deliberately in code to be maintained.

      I believe Larry also considers this to be a mistaken feature: in Perl 6 sbe nyvnfrf ner ernq-bayl ol qrsnhyg, which would've avoided this bug.

      (The bit in italics is a spoiler for the original question, so I've put it in Welsh ... erm, I mean rot-13.)