in reply to Avoiding if/else knots

loris,
You probably want to take a look at Implementing Dispatch Tables. The trouble with dispatch tables in Perl is that the conditions need to be exact keys. In other words, if you want any value integer in the range 1-999 to do the same thing, you need to create keys for each of those integers. There are ways around this in certain situations which is why I suggest reading that tutorial.

Update: s/value/integer/ pointed out by xdg++

Cheers - L~R

Replies are listed 'Best First'.
Re^2: Avoiding if/else knots
by xdg (Monsignor) on Aug 18, 2006 at 13:28 UTC
    The trouble with dispatch tables in Perl is that the conditions need to be exact keys. In other words, if you want any value in the range 1-999 to do the same thing, you need to create keys for each of those integers.

    If you need integers in a range, you've still got a discrete set of values and mapping that to the dispatch table isn't hard.

    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.

      When dealing strictly with small positive integers like in your example, an array might be better than a hash.

      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]->();
      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.

      Cheers - L~R

        No offense, but you really haven't added anything to what I said.

        Well, we can agree to disagree.

        You said 'if you want any value in the range 1-999' but then said 'each of those integers'. Those aren't the same thing. My post was an attempt to differentiate the easy case (integers) from the hard case (non-integers).

        -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.

Re^2: Avoiding if/else knots
by tilly (Archbishop) on Aug 19, 2006 at 03:50 UTC
    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.

Re^2: Avoiding if/else knots
by holli (Abbot) on Aug 18, 2006 at 16:49 UTC
    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; }


    holli, /regexed monk/
      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.

      Cheers - L~R