dispatch table
call code ref based on a key
isa
is a key valid? (not same as in a set). isa usually works on
fixed sets of keys
my @foos = qw( axxj djdj whwh ) ;
my %is_a_foo = map { $_ => 1 } @foos
mapping/conversion
short month to long month
records
single row from a db or similar
data structures
hash refs are the core to most deeper data structures
sets
set of active objects in a class. plenty of other examples
sparse arrays
saves major space when you have very few entries in a
very large array.
thanx,
uri
--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
I don't have any additional uses for hashes to add, but I do have a
great hash initializer I picked up from Damian when he was in town a
few years ago (borrowing from your example):
my @foos = qw( axxj djdj whwh ) ;
my %is_a_foo;
@is_a_foo{@foos} = (1) x @foos;
It runs *way* faster than the $_ aliasing does in the map (at least by
my benches). I thought that was fun when I saw it.
Scott
--
Scott Wiersdorf
sc...@ipartner.net
#!/usr/bin/perl
use strict;
use warnings;
# Unqiueness
{
my @list = qw( a b c x y z a b c );
my %unique = ();
@unique{@list} = @list;
@list = keys %unique;
print "@list\n";
}
# Counts
{
my @list = qw( a b c x y z a b c );
my %counts = ();
$counts{$_} ++ for @list;
print "$_ : $counts{$_}\n" for keys %counts;
}
__END__
--
Just my 0.00000002 million dollars worth,
Shawn
+------------\
| Shangri La \
| 40,000 km /
+------------/
You might want to explain yourself in fuller, properly punctuated, detail there
(particularly since it seems to not be about hashes per se)
--
Free map of local environmental resources: http://CambridgeMA.GreenMap.org
--
MOTD on Boomtime, the 35th of The Aftermath, in the YOLD 3173:
You don't need a Swiss Army knife to cut yourself, a piece of paper will do just fine. --JP
=>
=>too long has this list been quiet. but i have a fun question. i am
=>writing up slides for an all about hashes class. one goal i have is to
=>list and explain as many different uses for hashes as reasonably
=>possible. i have a short list to start with but i am sure the hive mind
=>of fwp can scrape up a bunch more. each one should have a name and not
=>overlap too much with any of this list (my initial list should be
=>obvious to you).
=>
=> dispatch table
=>
=> call code ref based on a key
=>
I admit I'm better with python these days than I am with perl, but one of
the caveats that the dispatch table should be taught with is that
selecting the correct code ref is different from calling through it.
Given:
table = { ... }
eg
ref = table{ expr }
ref()
is different from
table{expr}()
The latter can be a bear to debug ;-)
--
Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net
=>>I admit I'm better with python these days than I am with perl, but one of
=>>the caveats that the dispatch table should be taught with is that
=>>selecting the correct code ref is different from calling through it.
=>
=>You might want to explain yourself in fuller, properly punctuated,
=>detail there (particularly since it seems to not be about hashes per se)
Sorry, I thought I was clear and properly punctuated.
Given:
table = { ... }
eg
ref = table{ expr }
ref()
is different from
table{expr}()
The latter can be a bear to debug ;-)
In the second case, you're calling a function which can produce any error
that all of the functions in table are capable of generating. This may
also include an illegal reference into table in the first place. In the
first example, you eliminate the indexing into the dispatch table as a
seperate step from actually making a subroutine call.
>In the second case, you're calling a function which can produce any error
>that all of the functions in table are capable of generating.
I have no idea what you mean by this, are you sure you're not carrying over
some freaky Python conventions to Perl?
>This may also include an illegal reference into table in the first place.
Yes, and?
>In the first example, you eliminate the indexing into the dispatch table as a
>seperate step from actually making a subroutine call.
That's an phrase. Regardless, your proposal still would not solve the problem
of using a non-existent subruotine, for that you'd need:
exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
warn "Key <$sub> does not exist in the dispatch table";
( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
--
*AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(",$\/"," ")[defined wantarray]/e;$1}
&Just->another->Perl->hack;
#Aristotle Pagaltzis // <http://plasmasturm.org/>
SW> I don't have any additional uses for hashes to add, but I do have a
SW> great hash initializer I picked up from Damian when he was in town a
SW> few years ago (borrowing from your example):
SW> my @foos = qw( axxj djdj whwh ) ;
SW> my %is_a_foo;
SW> @is_a_foo{@foos} = (1) x @foos;
very old and i covered it in my hash slice tutorial:
http://sysarch.com/Perl/hash_slice.txt
SW> It runs *way* faster than the $_ aliasing does in the map (at least by
SW> my benches). I thought that was fun when I saw it.
even faster is
@is_a_foo{@foos} = () ;
and then use exists() to test instead of truth.
SHC> # Unqiueness
SHC> {
SHC> my @list = qw( a b c x y z a b c );
SHC> my %unique = ();
SHC> @unique{@list} = @list;
SHC> @list = keys %unique;
SHC> print "@list\n";
SHC> }
SHC> # Counts
SHC> {
SHC> my @list = qw( a b c x y z a b c );
SHC> my %counts = ();
SHC> $counts{$_} ++ for @list;
SHC> print "$_ : $counts{$_}\n" for keys %counts;
SHC> }
both good ones that i should have remembered. i will add them to the
list.
AP> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
>> exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
>> warn "Key <$sub> does not exist in the dispatch table";
AP> ( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
some variations on that:
my $sub = $dispatch{$key} or die "trying to call missing code" ;
$sub->() ;
or:
my %dispatch = (
foo => \&foo,
...
default => \&default
) ;
$key = 'default' unless exists( $dispatch{ $key } ;
$sub = $dispatch{ $key } ;
or:
my $sub = $dispatch{ $dispatch{ $key } ?
$key : $dispatch{ 'default' } } ;
or:
my $sub = $dispatch{ $key } || $dispatch{ 'default' } ;
as you can see there are various ways to handle a missing dispatch
key. this is not a hash issue but a detail about doing dispatch tables
cleanly. sometimes you want to predefine a default code ref in the
dispatch table and other times you want to handle the missing key when
you make the call through the dispatch table.
Your example would be clearer if writing in Perl. Do you mean?
%table = (
foo => \&foo,
# ...
);
Or?
$table = {
foo => \&foo,
# ...
};
So why did you skip the check for whether the default value is
a CODE ref?
Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>
Shouldn't this be?
my $sub = $dispatch{ $dispatch{ $key }
? $key
: 'default'
};
>
> or:
>
> my $sub = $dispatch{ $key } || $dispatch{ 'default' } ;
>
>
> as you can see there are various ways to handle a missing dispatch
> key. this is not a hash issue but a detail about doing dispatch tables
> cleanly. sometimes you want to predefine a default code ref in the
> dispatch table and other times you want to handle the missing key when
> you make the call through the dispatch table.
>
> uri
>
Or:
my $sub = ( exists $dispatch{ $key } && ref( $dispatch{ $key } ) eq 'CODE' )
? $dispatch{ $key }
: $dispatch{ 'default' };
Just because you're not paranoid doesn't mean computers don't hate you :)
Because I don't like dispatch tables. When I see them I want to convert the whole thing to objects and starting thinking about inheritance and polymorphism. Which will take care of such problems at "compile" time.
But this thread is about hashes not objects.
(And I still think computers hate me.)
> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
> > exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
> > warn "Key <$sub> does not exist in the dispatch table";
>
> ( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
>
or &{ ... || ... }->()
just to avoid problems like:
print ( $dispatch{$sub} || sub { warn } )->();
--
Vladi Belperchinov-Shabanski <ca...@biscom.net> <ca...@datamax.bg>
http://cade.datamax.bg/ pgp/gpg key id: 6F35B214 (pgp.mit.edu)
--
equally destructive as we are, don't you think we've also gone too far?!
And you wonder why I dislike dispatch tables? So simple in concept, so ugly in reality.
SHC> A. Pagaltzis wrote:
>> * Mr. Shawn H. Corey <shawn...@magma.ca> [2007-11-24 00:50]:
>>> my $sub = ( exists $dispatch{ $key } && ref( $dispatch{ $key } ) eq 'CODE' )
>>> ? $dispatch{ $key }
>>> : $dispatch{ 'default' };
>>>
>>> Just because you're not paranoid doesn't mean computers don't
>>> hate you :)
>> So why did you skip the check for whether the default value is
>> a CODE ref?
SHC> Because I don't like dispatch tables. When I see them I want to
SHC> convert the whole thing to objects and starting thinking about
SHC> inheritance and polymorphism. Which will take care of such
SHC> problems at "compile" time.
and how would an object remove the need for a dispatch table? you can't
always map keys to methods and OO isn't needed in all cases. you can
also do dispatch tables inside a class and again much simpler than OO or
polymorphism. inheritance is right out as it is baggage in most
designs. people think OO eq inheritance and that is so wrong. i prefer
message passing and its flavor of polymorphism any day over inheritance
and its rigid class hierarchies and dependency trees.
SHC> But this thread is about hashes not objects.
SHC> (And I still think computers hate me.)
not as much as i hate (but have used) inheritance. i should start a side
thread for this: ever write an OO system where one class ISA and HASA
another class at the same time? i have and for a good reason and it
works so elegantly. :)
thanx,
DB> Tied hashes a la Regexp::Common.
i don't consider tied hashes to be a common use of hashes. and exploring
tie will be way beyond the scope of this lesson anyhow.
SHC> Vladi Belperchinov-Shabanski wrote:
>> On Fri, 23 Nov 2007 23:18:20 +0100
>> "A. Pagaltzis" <paga...@gmx.de> wrote:
>>
>>> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
>>>> exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
>>>> warn "Key <$sub> does not exist in the dispatch table";
>>> ( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
>>>
>> or &{ ... || ... }->()
>> just to avoid problems like:
>> print ( $dispatch{$sub} || sub { warn } )->();
SHC> And you wonder why I dislike dispatch tables? So simple in
SHC> concept, so ugly in reality.
s/dispatch tables/inheritance/g ;
:)
[...]
> or:
>
> my $sub = $dispatch{ $key } || $dispatch{ 'default' } ;
Why stop there? Assuming $key never evaluates to 0:
my $sub = $dispatch{ $key || 'default' };
If it does, wait until 5.10 comes out and:
my $sub = $dispatch{ $key // 'default' };
Although there really is little point stuffing the coderef into a
scalar, it's not like there's anything you can do to it. It's clearer to
not draw attention to it and just run the damned thing:
$dispatch{ $key || 'default' }->();
David
> >>>>> "SHC" == Shawn H Corey <shawn...@magma.ca> writes:
>
> SHC> Vladi Belperchinov-Shabanski wrote:
> >> On Fri, 23 Nov 2007 23:18:20 +0100
> >> "A. Pagaltzis" <paga...@gmx.de> wrote:
> >>
> >>> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
> >>>> exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
> >>>> warn "Key <$sub> does not exist in the dispatch table";
> >>> ( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
> >>>
> >> or &{ ... || ... }->()
> >> just to avoid problems like:
> >> print ( $dispatch{$sub} || sub { warn } )->();
>
> SHC> And you wonder why I dislike dispatch tables? So simple in
> SHC> concept, so ugly in reality.
>
> s/dispatch tables/inheritance/g ;
>
> :)
s/inheritance/destructors/g ;
:o)
/Bernie\
--
Bernie Cosell Fantasy Farm Fibers
mailto:ber...@fantasyfarm.com Pearisburg, VA
--> Too many people, too few sheep <--
Your dispatch table has keys for all nonzero strings?
That’s one big hash.
> Uri Guttman writes:
> >>>>>> "AP" == A Pagaltzis <paga...@gmx.de> writes:
> >
> > AP> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
> > >> exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
> > >> warn "Key <$sub> does not exist in the dispatch table";
> >
> > AP> ( $dispatch{$sub} || sub { warn "no such action '$sub'" } )->();
> >
> > some variations on that:
> >
> > my $sub = $dispatch{$key} or die "trying to call missing code" ;
> > $sub->() ;
> >
> > or:
>
> [...]
>
> > or:
> >
> > my $sub = $dispatch{ $key } || $dispatch{ 'default' } ;
>
>
> Why stop there? Assuming $key never evaluates to 0:
>
> my $sub = $dispatch{ $key || 'default' };
usual case would be there is no value (coderef) for the key, not empty key!
>
> If it does, wait until 5.10 comes out and:
>
> my $sub = $dispatch{ $key // 'default' };
>
> Although there really is little point stuffing the coderef into a
little? really? I'd rather handle situation when $sub is empty.
shuldn't happen or get logged (debug obviously) for example.
> scalar, it's not like there's anything you can do to it. It's clearer to
> not draw attention to it and just run the damned thing:
>
> $dispatch{ $key || 'default' }->();
>
Which still may trigger "Can't use string ("") as a subroutine ref while "strict refs" in use at ..."
:)
> David
DL> Uri Guttman writes:
>>>>>>> "AP" == A Pagaltzis <paga...@gmx.de> writes:
AP> * Jerrad Pierce <belg...@MIT.EDU> [2007-11-23 22:50]:
>> >> exists( $dispatch{$sub} ) ? $dispatch{$sub}->() :
>> >> warn "Key <$sub> does not exist in the dispatch table";
AP> ( $dispatch{$sub} || sub { warn "no such action '$sub'" }
>> )->();
>> some variations on that:
>> my $sub = $dispatch{$key} or die "trying to call missing code" ;
>> $sub->() ;
>> or:
>> my $sub = $dispatch{ $key } || $dispatch{ 'default' } ;
DL> Why stop there? Assuming $key never evaluates to 0:
DL> my $sub = $dispatch{ $key || 'default' };
and what if $key is true but not found?? that is a different
problem. your code doesn't handle that, it only handles a false or missing key
DL> If it does, wait until 5.10 comes out and:
DL> my $sub = $dispatch{ $key // 'default' };
same problem.
DL> Although there really is little point stuffing the coderef into a
DL> scalar, it's not like there's anything you can do to it. It's clearer to
DL> not draw attention to it and just run the damned thing:
DL> $dispatch{ $key || 'default' }->();
there are places where you want to delay the call. you may need to pass
the code ref around or call it multiple times or with different args. i
have found that getting the sub is better as a separate step from
calling it.
> DL> Why stop there? Assuming $key never evaluates to 0:
>
> DL> my $sub = $dispatch{ $key || 'default' };
>
> and what if $key is true but not found?? that is a different
> problem. your code doesn't handle that, it only handles a false or missing key
>
> DL> If it does, wait until 5.10 comes out and:
>
> DL> my $sub = $dispatch{ $key // 'default' };
>
> same problem.
>
> DL> Although there really is little point stuffing the coderef into a
> DL> scalar, it's not like there's anything you can do to it. It's clearer to
> DL> not draw attention to it and just run the damned thing:
>
> DL> $dispatch{ $key || 'default' }->();
>
> there are places where you want to delay the call. you may need to pass
> the code ref around or call it multiple times or with different args. i
> have found that getting the sub is better as a separate step from
> calling it.
I see what you and Aristotle are saying. In my own code I arrange things
so that you're never actually feeding random strings into the dispatch
table, I make sure the values are restricted to a finite domain
beforehand, so I can't say I've been bitten by that.
And point taken re: calling it multiple times.
David
DL> Although there really is little point stuffing the coderef into a
DL> scalar, it's not like there's anything you can do to it. It's clearer to
DL> not draw attention to it and just run the damned thing:
DL> $dispatch{ $key || 'default' }->();
>> there are places where you want to delay the call. you may need to pass
>> the code ref around or call it multiple times or with different args. i
>> have found that getting the sub is better as a separate step from
>> calling it.
DL> I see what you and Aristotle are saying. In my own code I arrange things
DL> so that you're never actually feeding random strings into the dispatch
DL> table, I make sure the values are restricted to a finite domain
DL> beforehand, so I can't say I've been bitten by that.
and how do you do that restricting? sounds like a hash is needed there
too! :) and with outside input as in web you need to do this checking in
the server. if you know the data is clean then you can default on a
missing key but otherwise you need to check the key against the dispatch
table.
for my $user (@filenames) {
open(my $fh, "<", $user) {
while(<$fh>) {
$use{$user}{$1} = 1 while /include\s*['"](.*?)['"]/g;
}
}
It's a full graph, with fast looking and iteration over outgoing edges.
The quick existence lookup is nice while building it, but if you don't
care about that, then it's cleaner to encode it as a map from node to
array ref of children:
$children{A} = [ 'B', 'C', 'D' ];
$children{C} = [ 'E', 'F' ];
...etc...
There's sort of another use buried in there, too: hashes can be used
to map object identifiers to their data (a la inside-out objects or
something simpler that is just trying to keep the real data in a
canonical place, perhaps to avoid worrying about cyclic references.)
For an obscure and rather unsafe usage, you could use hashes for randomization:
my @quiz_questions = ...;
my %quiz_table;
@quiz_table{@quiz_questions} = ();
my ($random_first_question) = keys %quiz_table;
while my $question (keys %quiz_table) {
print "QUESTION: $question ";
my $answer = <STDIN>;
...;
}
Hashes can be used for caches or memoization:
our $answer;
sub func {
return $answer ||= ...compute...;
}
Hashes can be used for sparse arrays:
$arr{10} = "X";
$arr{83719} = "Y";
Hashes can be used for symbol tables. :-)
SF> I don't think this has been mentioned, although it's really just a
SF> combination of two existing ones: I often have a table of sets.
SF> for my $user (@filenames) {
SF> open(my $fh, "<", $user) {
SF> while(<$fh>) {
SF> $use{$user}{$1} = 1 while /include\s*['"](.*?)['"]/g;
SF> }
SF> }
SF> It's a full graph, with fast looking and iteration over outgoing edges.
i consider graphs a variant of deep (and cyclical) data structures. and
i think they are more complex than the other simple hash uses. also
graphs are too hard to explain in one slide for this class. but i will
keep it in mind as another use. all the classic linked list structures
can be easily done with hashes for sure.
SF> There's sort of another use buried in there, too: hashes can be
SF> used to map object identifiers to their data (a la inside-out
SF> objects or something simpler that is just trying to keep the real
SF> data in a canonical place, perhaps to avoid worrying about cyclic
SF> references.)
i use a hash to track all objects created by a class. the fun part is
that the key and value were the same thing. but the key gets stringified
which is why you still need the ref/object as the value.
SF> Hashes can be used for caches or memoization:
SF> our $answer;
SF> sub func {
SF> return $answer ||= ...compute...;
SF> }
caching is a good one. that is all that memoize uses.
SF> Hashes can be used for sparse arrays:
SF> $arr{10} = "X";
SF> $arr{83719} = "Y";
i mentioned that one.
SF> Hashes can be used for symbol tables. :-)
true. i didn't mention that. but i always teach to use hashes for data
and not the symbol table (via symrefs). mung the symbol table only when
you need to mung it!
thanx,
my %seen;
for my $value (@values) {
next if $seen{$value}++;
# Do processing with $value here.
}
--
Keith C. Ivey <ke...@iveys.org>
Washington, DC
Well, in a strict sense it IS the same, as it is just one
of many possible set operations. I suppose you could say
it's a subset of sets. :-) I think you're trying to focus
on the difference between sets of strings, which are the
hash keys() directly, and sets of other things (e.g. objects),
which are hash values(). You also emphasize the const-ness
of the "isa" key set, which I think is rather too narrow.
I think a better approach would be to talk about sets in
general, the many set operations (including the *missing*
operations, which have to be kludged in Perl), the set-
related CPAN modules, and how all these things can be used.
JMHO. Sorry if someone already made this point and I missed
it.
--
John Douglas Porter
____________________________________________________________________________________
Be a better pen pal.
Text or chat with friends inside Yahoo! Mail. See how. http://overview.mail.yahoo.com/
JDP> Uri wrote:
>> isa
>> is a key valid? (not same as in a set).
>> isa usually works on fixed sets of keys
JDP> Well, in a strict sense it IS the same, as it is just one
JDP> of many possible set operations. I suppose you could say
JDP> it's a subset of sets. :-) I think you're trying to focus
JDP> on the difference between sets of strings, which are the
JDP> hash keys() directly, and sets of other things (e.g. objects),
JDP> which are hash values(). You also emphasize the const-ness
JDP> of the "isa" key set, which I think is rather too narrow.
JDP> I think a better approach would be to talk about sets in
JDP> general, the many set operations (including the *missing*
JDP> operations, which have to be kludged in Perl), the set-
JDP> related CPAN modules, and how all these things can be used.
JDP> JMHO. Sorry if someone already made this point and I missed
JDP> it.
i do plan on covering sets in their own right along with intersection
and union operations too (right out of the FAQ). but i still think isa
is a (sic) concept that is important enough to cover on its own. sure it
is a set but a very specific type with its own name. the names of these
concepts are important (almost like design patterns which i despise
:). i have seen too many newbies and even some mildly experienced perl
hackers don't know all these hash uses (or their names). ever see the
(virtual) glassy eyes when you mention dispatch tables in polite public?
:)
i am aiming this for my class which is a mix of experienced hackers down
to some ex-cobol coders who code perl because they get paid for it. and
it is also for future classes or writings. so i want to cover as many
uses at a basic level and not get into subtleties such as which are
really variations of each other. they are all hash variations when you
come down to that so the context and name of each use must be clearly
explained.
i will post here the url for these slides (with mistakes! :) when i get
them done. please be kind. :)
True, I guess, but lots of these uses are the same. In Uri's original
post, "isa" could be considered the same as "sets", and "records" the
same as "data structures".
With a %seen hash, the count is being calculated, but it's not being
used except as a boolean, and it's a fairly common idiom. I'd say
that's a separate use, but of course Uri can judge.
perl -MIO::File -ane '($fds{$F[1]} ||= IO::File->new(">$F[1]"))->print($_)' < bigfile
Brian
I often use them to divide one big file into several
small files named after some field in each line, e.g.
KI> Jerrad Pierce wrote:
>>> How about using a hash to keep track of which things you've already handled?
>> That's just the afore-mentioned count
KI> True, I guess, but lots of these uses are the same. In Uri's original
KI> post, "isa" could be considered the same as "sets", and "records" the
KI> same as "data structures".
KI> With a %seen hash, the count is being calculated, but it's not being
KI> used except as a boolean, and it's a fairly common idiom. I'd say
KI> that's a separate use, but of course Uri can judge.
i have never run into a situation where i may process some items and
later some more and need to track them with a hash. it doesn't mean that
isn't a good use but i don't see why it couldn't be done
differently.
then again, i eschew else clauses which is rare. i just seem to code in
a way that i very rarely need them. and i am not talking obscure code,
just judicious use of statement modifiers, subs, logic order that
generally eliminates the need for else. others will use else as they
please.
If names are that important to you, then you should use the right
ones. I've never seen this set membership test thing you've
illustrated called "isa". To most programmers, "isa" means
something else. Oops - s/else/different/; sorry. ;-)
--
jdp