Re: Avoiding if/else knots
by Limbic~Region (Chancellor) on Aug 18, 2006 at 12:53 UTC
|
| [reply] |
|
|
use strict;
use warnings;
sub action_1_to_999 {
print "1 to 999\n";
}
my %dispatch = (
0 => sub { print "Zero\n" },
map { $_ => \&action_1_to_999 } ( 1 .. 999 ),
1000 => sub { print "1e3\n" },
);
$dispatch{0}->();
$dispatch{23}->();
The challenge is for non-integer conditions or non-bounded ones. What if N > 1000? What if N = 3.14159265358979323? What if N = 'PI'? In that case, you still need to have the advance logic, if/else or otherwise, to convert inputs to a smaller number of well-defined cases.
My advice in that case is keep the case logic in one place and the actions all somewhere else via subroutines. Dispatch tables probably don't help unless you're already starting with a discrete, bounded set of inputs (or need to dynamically add cases as your program runs).
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
| [reply] [d/l] |
|
|
sub action_1_to_999 {
print "1 to 999\n";
}
my @dispatch = (
sub { print "Zero\n" },
map { \&action_1_to_999 } ( 1 .. 999 ),
sub { print "1e3\n" },
);
$dispatch[0]->();
$dispatch[23]->();
| [reply] [d/l] |
|
|
xdg,
No offense, but you really haven't added anything to what I said.
To quote myself, "The trouble with dispatch tables in Perl is that the conditions need to be exact keys". I didn't say that creating a range was hard, I said "you need to create keys for each of those integers".
In other words, there is no short-cut to make that a single key and anything that can't be done as a straight lookup (requires logic) doesn't work. That is, it doesn't work without additional if/elsif/else knots to determine the correct key to dispatch.
| [reply] |
|
|
|
|
|
|
| [reply] [d/l] |
|
|
I have handled this problem before by having an array of pairs of functions - the first tests whether this is the right case, the other does it. You dispatch something like this:
for my $case (@cases) {
if ($case->[0]->(@data)) {
$case->[1]->(@data;
last;
}
}
and then you just put whatever you want into @cases.
This is for more complex code cleanup. For instance suppose one might have a number of possibilities which need to be included only if some global condition is true. The standard if/elsif/else construct would require testing that condition in lots of elsifs. Lots of repeated code. This approach allows you to replace that with testing that condition once, then shoving a bunch of stuff into @cases if it is true.
Note that this is not a common need. It should not be a normal part of your toolbox. I think I've only resorted to the technique 2 or 3 times. | [reply] [d/l] |
|
|
My approach to that problem would be to write function to map the input to the keys in the hash. Something like
$dispatch{calculate_key{$input}}->(%attr);
sub calculate_key
{
#..
return $key;
}
| [reply] [d/l] |
|
|
holli,
Sure except that calculate_key() is going to contain the same if/elsif/else knot that the OP is asking to avoid. The bottom line is that if your conditions are not exact keys then using dispatch tables will not avoid the knot. That isn't to say that it can't help make the code cleaner.
| [reply] |
Re: Avoiding if/else knots
by izut (Chaplain) on Aug 18, 2006 at 12:28 UTC
|
my %functions = (
'this' => sub { ... },
'that' => \&do_something,
);
my %attrs = (...);
my $key = 'this';
$functions{$this}->(\%attrs);
Hope this helps.
Igor 'izut' Sutton
your code, your rules.
| [reply] [d/l] |
Re: Avoiding if/else knots
by Fletch (Bishop) on Aug 18, 2006 at 12:39 UTC
|
The technique's perfectly valid and is usually known as a 'dispatch table' (if you're looking for a search term).
| [reply] |
Re: Avoiding if/else knots
by jdporter (Paladin) on Aug 18, 2006 at 19:52 UTC
|
| [reply] |
|
|
switches are awesome for simple short cases. hashes for complex ones. pick yer poison. :)
| [reply] |
|
|
I could say the reverse as well.
Hash-based dispatch tables have a significant limitation: they're hash based. That means any condition you look up by has to be a hash key, which means it (or its stringification) has to exist in the hash. Of course, you can increase your flexibility in this area by using some of the funky TIEHASH modules available on CPAN, such as Tie-Hash-Approx, Tie-Hash-KeysMask, Tie-Hash-Regex, and Tie-RangeHash. But in the general case, I believe switches are more powerful because (at least in the typical Perl implementations) there are no limitations on the conditions. Switches also give you defaults, which can be hard to do with hashes without the aid of special tie modules, and fallthrough, which is even harder. Try writing this using a dispatch table:
use Switch::Perlish;
switch $var, sub {
case sub { $_[0] > 9 }, sub { warn "$var>9"; fallthrough };
case 9, \&found_it;
default \¬_found;
};
We're building the house of the future together.
| [reply] [d/l] |
Re: Avoiding if/else knots
by Codon (Friar) on Aug 21, 2006 at 17:00 UTC
|
I recently had to tackle something similar (yet different) in my work. I had half a dozen conditions to check and various combinations resulted in counting items in different ways. I knew that there had to be a better way than having a page of if/elsif/else (actually, it was a nested ternary, but it functioned the same).
After spending a while thinking about it (load the problem into memory; take it home; let it run in the background) I saw that at the heart of the problem I was filtering things. I don't know if that's quite the same for you (not enough details in the OP). I essentially had a request that was looking for things that had a certain set of attributes. I was comparing the attributes of the request to the attributes of each item in the list to find matches and count matches / misses accordingly. I worked up a solution that defined a record filter by setting up a bit mask indicating which attributes I was looking for. Then as I looked at each record that I needed to filter, I set bit flags according to the attributes of the record. Then a bit-wise & told me if I got a match.
Assuming that this even comes close to resembling your problem, you could use the discrete bit-wise results as keys in you dispatch table. The values would be the methods to dispatch to for each case.
Ivan Heffner
Sr. Software Engineer, DAS Lead
WhitePages.com, Inc.
| [reply] [d/l] |
Re: Avoiding if/else knots
by EvanK (Chaplain) on Aug 18, 2006 at 18:11 UTC
|
disregard my post, i misread the OP. | [reply] |