Wednesday, December 20, 2006

Perl: Beware when counting array elements

Sometimes it's the simple things that put a halt to my productivity. In fact, it's rarely the big things. Master Yoda gave us an excellent phrase to consider when addressing a programming problem: "Judge me by my size do you? And well you should NOT!".

When I need to check how big an array is in Perl, it's quite intuitive to access that value using the $#array_name special variable. It works like a charm. But what happens when the array you need to count elements in is a referenced array?

A typical de-reference operation would be @$array_reference. This gives us the underlying array. Forgetting my Jedi training, I allowed the Dark Side to i$nfluence me as I flailed through syntactic permutations.


$$#array_reference
@$#array_reference
$#{$array_reference}


Much to my dismay, these futile expressions continued to plague me. I then focused my energies, and put the blast shield down.

...From WikiQuote

Ben: Remember a Jedi can feel the Force flowing through him.
Luke: You mean it controls your actions?
Ben: Partially, but it also obeys your commands.
Han: Hokey religions and ancient weapons are no match for a good blaster at your side, kid.
Luke: [to Han] You don't believe in the Force, do you?
Han: Kid, I've flown from one side of this galaxy to the other. I've seen a lot of strange stuff, but I've never seen anything to make me believe there's one all-powerful Force controlling everything. There's no mystical energy field controls my destiny! It's all a lot of simple tricks and nonsense.
Ben: I suggest you try it again Luke. This time, let go your conscious self and act on instinct.
[Ben places a helmet on Luke's head with the blast-shield down to blind him]
Luke: But with the blast shield down I can't see a thing!
Ben: Your eyes can deceive you. Don't trust them. Stretch out with your feelings.
[Luke calmly evades and deflects three pulses from the remote, successfully using the Force]
Han: I call it luck.
Ben: In my experience, there's no such thing as luck.
Han: Look. Good against remotes is one thing. Good against the living…that's something else.
Ben: [to Luke] You've taken your first step into a larger world.


I wrote a quick code fragment to isolate the problem and experiment with it. In doing so, I was reminded of the true nature of dereferencing and array contexts.


#!/usr/bin/perl -w
use strict;

my @a = qw(one two three four five six);
my $aref = \@a;

print "Number of elements in the array: $#a\n";
print "Number of elements in the array (ref): " . @$aref . "\n";


Looking at this code, ask yourself what values will be produced in each print statement. With carelessness likened to use of a blaster, one may assume they will produce the same integer. In fact they will not; A fact whose presence will be known through the Force. Let's take a closer look at these expressions.

@a is a literal array. The $# special variable is a direct vector to the last element used by that array. Knowing that Perl indexes its arrays beginning at zero, we then know this line will print the integer 5.

@$aref is a de-referencing operation. It represents the literal array, rather than the scalar that points to it. In this case, we are printing the array in scalar context, which will evaluate to the number of elements in the array: 6.

A simple problem with a not-so-simple explanation. What if your code had thousands of elements in it... Would your test plan have covered this condition when you decided to use referenced arrays rather than literals in one of your code branches? Remember that the Jedi Code tells us ...there is no ignorance; there is knowledge. Code, and learn.

No comments: