The fundamental key IMHO is this. As long as you are doing
a lot of thinking involving positional logic, you are not
being very Perlish. What this means is that you use
implicit looping operations (foreach over a list rather
than a C-style for,
map,
grep) and use hashes to do
things by name. To get a good sense I can suggest nothing
better than getting the Cookbook and looking through the
examples in there.
Short of that I highly recommend the section in Camel II
(possibly in Camel III as well?) in chapter 1 on how Perl
data structures map to linguistic operations. The
linguistic version of a hashlookup is the word "of". This
informs us how we name a hash. If the hash gives us the
address of the person, we should say $address{$person}. If
it is possible to get an address in several ways we might
be more verbose and say $address_by_person{$person}. In
either case "talk your way" through the problem in English
and wherever you say "of" or an equivalent, that is a good
sign that you want a hash.
That said, here are some standard uses that I have for
them:
- The obvious lookup.
$address{$person};
- Keep track of existing things I have dealt with.
Where I might say, "If I haven't seen this one yet (BTW
mark it seen) then..." I might write in code:
if (not $is_seen{$case}++) { # etc
- Named function arguments. Rather than having to
remember a set of 6 arguments in order, and what the
defaults are if you need to set the 6'th but not touch the
3'rd, 4'th, or 5'th, just use a hash:
sub my_function {
my %opts = @_;
# etc
and it is easier to remember how to call the function, and
easier to add more useful options later.
- Structs. Anywhere you would have used a pointer to a
struct in C, you can use a reference to a hash in Perl.
The notation is even similar since the arrow is used in Perl
for dereferencing. This is why you see a lot of OO code in
Perl with things like:
my $name = $self->{name};
- List special cases. You can easily enumerate special
cases in a hash. If you are willing to create anonymous
functions for them (with sub) then you can easily create
a nice catch-all special case:
if (exists $handler{$case}) {
$handler{$case}->(); # Handle the special case
}
The actual definitions of the special cases are placed
elsewhere. Lest this idea just sound weird, you may want
to read Why I like functional programming. (It helps to read the *last* function
first - scrub_input - and understand what it does. It may
also help to check out what pos does.) OK, perhaps you
don't want to try that. Yet.
And so it goes. Whenever it makes sense to refer to things
by name, it makes sense to use hashes.
UPDATE
Forgot a ++ on $is_seen{$case}. I thought it, and
verbalized it in English, but when I went to write the Perl
at last I apparently forgot it at the last moment...