[ABE.pm] perl 5.12! - container improvements

Ricardo Signes perl.abe at rjbs.manxome.org
Sat May 15 12:09:53 PDT 2010


Containers!  You know!  Containers!  Like arrays and hashes.  They're kinda
better now.

One significant change is the availability of "each" for arrays.  For hashes,
each looks like this:

  while (my ($k, $v) = each %hash) { ...  }

Now you can write this:

  while (my ($i, $v) = each @array) { ...  }

This is part blessing and part curse.  The behavior of "each" is sort of weird,
in that the iterator is tied to the variable.  If you nest "eaches," you get
screwed.  Still, if everybody limits use of each to simple blocks, this can be
a nice little time-saver.  The alternative, by the way, is:

  for my $i (0 .. $#array) { my $v = $array[$i]; ...; }

=========

On a somewhat more esoteric note, you can now locally delete hash entries.
"What??" you ask?  Well, it's actually really really simple.  You won't need it
often, but when you do, it is great.

The "local" keyword can be used to change a global variable in dynamic scope.
Dynamic scope just means "until the current block of code ends."  That means
that if you call another routine, the local value stays in place.

Not everybody knows that you can use local on private (lexically-scoped)
hashes, to localize a key value.

  {
    my %h = (a => 1, b => 2);

    {
      local $h{a} = 10;
      say "a is $h{a}";
    }

    say "a is $h{a}";
  }

This will print:

  a is 10
  a is 1

Now, you can delete things locally:

  {
    my %h = (a => 1, b => 2);

    {
      delete local $h{a};
      say "a is $h{a}";
    }

    say "a is $h{a}";
  }

...and get:

  Use of uninitialized value $h{"a"} in concatenation (.) or string at - line 7.
  a is 
  a is 1

Again, this is one of those things you won't use every day, but it can save you
a lot of time and line noise.  Before, if you wanted to say "pass this hash to
another routine, just as it is, but without the 'debug' entry" you had to make
a copy or do bookkeeping:

  # Possibly expensive for very large hashes:
  my $result = do {
    my $copy = { %$orig };
    delete $copy->{debug};
    routine($copy);
  };

  # OR:

  # Horrible.
  my $result = do {
    my $existed = exists $orig->{debug};
    my $value   = delete $orig->{debug};
    my $result = routine($orig);
    $orig->{debug} = $value if $existed;
  };

Now, instead, you can just write:

  my $result = do {
    delete local $orig->{debug};
    routine($copy);
  };

=========

Finally, one change for the better that doesn't actually get you anything but
more warnings!  Assigning to $[ now generates a warning.  Why?  Because it is a
horrible thing to do, and nobody should ever do it or speak of it again, except
to curse its name.

Do you remember what it does?

  my @array = qw(a b c d e f);
  say "element 1 is $array[1]";

  $[ = 1;
  say "element 1 is $array[1]";

This will print:

  element 1 is b
  element 1 is a

So, right.  Changing $[ changes the starting index value of an array.  It is
pretty much always a horrible idea.  Now that it's been deprecated, it can go
away in a future version -- or at the very least continue to remind people, via
warning, that it's just utterly awful.

-- 
rjbs


More information about the ABE-pm mailing list