Question

I've come across the following line of code. It has issues:

  • it is intended to do the same as push
  • it ought to have used push
  • it's hard to read, understand
  • I've since changed it to use push
  • it does something I thought was illegal, but clearly isn't

here it is:

$array [++$#array] = 'data';

My question is: what does it mean to pre-increment $#array? I always considered $#array to be an attribute of an array, and not writable.

Was it helpful?

Solution

perldata says:

"The length of an array is a scalar value. You may find the length of array @days by evaluating $#days , as in csh. However, this isn't the length of the array; it's the subscript of the last element, which is a different value since there is ordinarily a 0th element. Assigning to $#days actually changes the length of the array. Shortening an array this way destroys intervening values. Lengthening an array that was previously shortened does not recover values that were in those elements."

Modifying $#array is useful in some cases, but in this case, clearly push is better.

OTHER TIPS

A post-increment will return the variable first and then increment it.

If you used post-increment you would be modifing the last element, since its returned first, and then pushing an empty element onto the end. On the second loop you would be modifing that empty value and pushing a new empty one for later. So it wouldn't work like a push at all.

The pre-increment will increment the variable and then return it. That way your example will always being writing to a new, last element of the array and work like push. Example below:

my (@pre, @post);

$pre[$#pre++] = '1';
$pre[$#pre++] = '2';
$pre[$#pre++] = '3';


$post[++$#post] = '1';
$post[++$#post] = '2';
$post[++$#post] = '3';

print "pre keys: ".@pre."\n";
print "pre: @pre\n";
print "post keys: ".@post."\n";
print "post: @post\n";

outputs:

pre keys: 3
pre: 2 3
post keys: 3
post: 1 2 3

Assigning a value larger than the current array length to $#array extends the array.

This code works too:

$ perl -le 'my @a; $a[@a]="Hello"; $a[@a]=" world!"; print @a'
Hello world!

Perl array is dynamic and grows when assign beyond limits.

First of all, that's foul.

That said, I'm also surprised that it works. I would have guessed that ++$#array would have gotten the "Can't modify constant" error you get when trying to increment a number. (Not that I ever accidentally do that, of course.) But, I guess that's exactly where we were wrong: $#array isn't a constant (a number); it's a variable expression. As such you can mess with it. Consider the following:

my @array = qw/1 2 3/;

++$#array;
$array[$#array] = qw/4/;

print "@array\n"

And even, for extra fun, this:

my @array = qw/1 2 3/;

$#array += 5;

foreach my $wtf (@array) {
  if (defined $wtf) {
    print "$wtf\n";
  }
  else {
    print "undef\n";
  }
}

And, yeah, the Perl Cookbook is happy to mess with $#array to grow or truncate arrays (Chapter 4, recipe 3). I still find it ugly, but maybe that's just a lingering "but it's a number" prejudice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top