[ABE.pm] perl 5.10 rules: state variables

Ricardo SIGNES rjbs-perl-abe at lists.manxome.org
Tue May 22 14:59:49 PDT 2007


I thought I'd inject some more actual technical content into the list by
sharing with you more information about perl 5.10 and how it is totally
awesome.  I'll try to send one email each day, until I get sick of it or run
out of interesting things to say.

Today's cool new feature: state variables

State variables make it even easier to write closures, which are subroutines
that have a way of remembering their state.  (They have "en-closed" variables.)

Closures allow subroutines to have their own private data that other code can't
muck with.  There are many advanced uses for these, and several simple
benefits.  One benefit is the encapsultion you can provide to your subroutines
-- in other words, by keeping their data private, you can prevent code
elsewhere from mucking with it.  (This puts a limit on your ability to do crazy
obnoxious things.  Some people see that as a drag, but I see it as an act of
kindness to your future self.

For example, if you want your program to count out hits from unique IPs, you
could write something like this:

  package IPCounter;

  use vars qw(%IP_HITS);

  sub hit_from {
    my ($ip) = @_;
    my $hits = $IP_HITS{ $ip } + 1;
    print "$hits from $ip\n";
  }

...but now any old jerk can write $IPCounter::IP_HITS{'127.0.0.1'} = 0
whenever and wherever he wants.  That jerk is likely to be you, and you'll
really get annoyed when this causes havok down the line.

You can already make a closure, like this:


  package IPCounter;

  {
    my %IP_HITS;

    sub hit_from {
      my ($ip) = @_;
      my $hits = $IP_HITS{ $ip } + 1;
      print "$hits from $ip\n";
    }
  }

This works, protecting %IP_HITS from outside interferences.  Unfortunately, it
looks weird to people who don't immediately realize that it's creating a
closure.  It also means you've got a sub being declared inside of a block and
not aligned to the left.  These are little weirdnesses, but all these little
weird things add up to produce scary code.

In Perl 5.10, you can write this:

  package IPCounter;

  sub hit_from {
    my ($ip) = @_;
    state %IP_HITS;

    my $hits = $IP_HITS{ $ip } + 1;
    print "$hits from $ip\n";
  }

%IP_HITS is only visible in the sub, but it keeps its value between calls to
the sub.  It's identical in function to the ugly code above, except it's not
ugly.

You can even have your state variables initialized, and the initialization will
only happen once.

  sub drink_a_beer {
    state $limit = 10;
    $limit--;

    die "I think that's about enough.\n" unless $limit;
  }

-- 
rjbs


More information about the ABE-pm mailing list