Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:

All,
I can see two ways to reduce duplication of code given the following snippet:
if ( $condition1 ) { if ( $condition2 ) { # Block1 } else { # Block2 } } else { # Block2 repeated again }
The first is the obvious choice to change Block2 into a subroutine. This doesn't feel right to me in this situation for some reason. There are quite a few variables that would need to be passed and keeping track of what is going on is getting difficult. It is obvious to me that refactoring is the right approach but the only alternative to a sub that I can think of is:
{ if ( $condition1 ) { if ( $condition2 ) { # Block1 last; } } # Block2 }

I do not like either of these choices which means I need to back up my refactoring to a higher level. With that said, I am still interested if anyone can think of a different way to eliminate the duplication. I am not going to provide the actual code because I am looking for generic alternatives. I know that given specific conditions there are clear winning options but that's not what I am after for now.

Cheers - L~R

Update: I am an idiot. I actually started out with RazorbladeBidet's solution below, but changed it because it didn't work as evaluation of the conditions has side effects. When I ended up with duplicated code I tried removing the duplicated code instead of the side effects. That's why a subroutine didn't feel right and it is also why refactoring at a higher level is the right thing to do.

Thanks for helping me see the forest through the trees.

Replies are listed 'Best First'.
Re: Better solution for code reduction?
by RazorbladeBidet (Friar) on Mar 10, 2005 at 17:00 UTC
    if ( $condition1 && $condition2 ) { # Block 1 } else { # Block 2 }

    ???
    --------------
    It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Better solution for code reduction?
by Keystroke (Scribe) on Mar 10, 2005 at 17:03 UTC
    You only execute Block1 if $condition1 and $condition2 is true.
    if ($condition1 && $condition2) { #Block1 } else { #Block2 }
Re: Better solution for code reduction?
by 5mi11er (Deacon) on Mar 10, 2005 at 17:01 UTC
    Does
    unless ($condition1 && $condition2) { #Block2 } else { #Block1 }
    fit what you're looking for?

    -Scott

    Update: Had the blocks reversed originally

    2nd Update: Which was correct, and I'd managed to confuse myself validating it.

Re: Better solution for code reduction?
by wfsp (Abbot) on Mar 10, 2005 at 17:09 UTC
    Block1 if $condition1 and $condition2 Block2 if !$condition2

    update:
    This solution is neat but, sadly, wrong! See 5mi11er below.

      I'd stared at this option a long time, and finally had to write out the truth table to fully see that this is not the same as the conditions originally put forth.

      Original code truth table: wfsp's code truth table: Condition1 Condition2 Execute Condition1 Condition +2 Execute ---------- ---------- ----------- ---------- --------- +- ----------- True True Block1 True True + Block1 True False Block2 True False + Block2 False True Block2 False True + none False False Block2 False False + Block2
      Also, since Block2 seems, in this generic example, to be the more important block of code, the unless form of the statement helps point that out (as I'd used in my original reply above)...

      -Scott

        5mi11er++

        I'd stared at this option a long time...

        So did I - but not long enough!

        Thanks for straightening it out.

        John

        And even if the second line was fixed so the truth tables would match, it's still wrong. The problem is that if the first set of conditions is true, Block1 will be run, before the second set of conditions is tested. However, running block1 may well change the true/false value of the second set of conditions.

        So it could not be the "generic solution" the OP was looking for.

Re: Better solution for code reduction?
by chb (Deacon) on Mar 11, 2005 at 08:08 UTC
    I saw your update, but I'll add my comment anyway... If you don't want to pass lots of variables to a subroutine, try an anonymous lexical sub that builds a closure over your current variable set, like (untested):
    { my $block2 = sub { # Block 2 code }; if ( $condition1 ) { if ( $condition2 ) { # Block1 } else { &$block2(); } } else { &$block2(); } }
Re: Better solution for code reduction?
by perlfan (Parson) on Mar 10, 2005 at 18:52 UTC
    This might be totally retarded, but could you do something like?
    eval "C$condition1"."_C$condition2"; sub C1_C1 { ... } sub C0_C1 { ... }
    This is assuming that the values of $condition1 and $condition2 will actually be "1" or "0".