Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

at continue, last

by djerius (Beadle)
on Jun 06, 2014 at 04:53 UTC ( [id://1088979]=perlmeditation: print w/replies, xml ) Need Help??

Update The imprecise nature of the language in this post has muddied the waters. The point of the post was to enumerate some ways of ensuring a single path for cleanup from a conditional clause, not all of them practical. My thanks to the respondents who persevered in spite of the muddiness of the water.

On to the original post...

I need to ensure that a variable is decremented regardless of how an if clause is exited, which might be in the middle of the block. I can code it this way:

if ( $condition1 ) {{ ... --$loop, last if $condition2; #bail! ... --$loop; }}
The repeated decrements are not DRY. This one is better:
if ( $condition1 ) { { ... last if $condition2; ... } --$loop; }
Along the way I stumbled upon these monstrosities:
for ( ; $condition1 ; $loop--, last ) { ... next if $condition2; ... }
Even worse:
while ( $condition1 ) { ... next if $condition2; ... } continue { --$loop; last; }
A last in a continue? Who knew?

Replies are listed 'Best First'.
Re: at continue, last
by BrowserUk (Patriarch) on Jun 06, 2014 at 13:03 UTC
    I need to ensure that a variable is decremented regardless of how an if clause is exited,

    Then do the decrement before entering the if:

    ... --$loop; if( condition1 ) { { ... last if condition2; ... } }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That'll break the program's logic; $loop may only be decremented within the conditional (otherwise, yes, I'd put it outside of it).
        That'll break the program's logic; $loop may only be decremented within the conditional (otherwise, yes, I'd put it outside of it).

        I that case, decrement it as the first thing in the conditional, then you're guaranteed it'll happen.

        The point is that, as described, there is no reason to employed contorted logic to achieve the described requirement.

        Perhaps in an attempt to simplify the original code you've omitted something that makes the contorted logic necessary, but as posted, it simply isn't needed.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: at continue, last
by InfiniteSilence (Curate) on Jun 06, 2014 at 14:25 UTC

    To me the secret to DRY (which is Do not Repeat Yourself -- I had to look that up) is to convert functionality to functions, encapsulate it in objects as methods that only execute in certain states, or to utilize some core language feature to reduce the code.

    From your desire, "I need to ensure that a variable is decremented regardless of how an if clause is exited.." it reads like you want the decrement operation to happen automatically when something else occurs -- a form of encapsulation -- like this:

    use strict; my $g_var = 1_000; sub special_dec { my $choice = shift; if ($choice) { --$g_var; } } my $thing = 'dog'; if ( $thing eq 'cat') { my $cntr = 0; while (++$cntr < 11) { last if (special_dec(900==900)); } } elsif ($thing eq 'dog') { my $cntr = 0; while (++$cntr < 11) { last if (special_dec(900==900)); } } print $g_var; 1; # of course prints 999

    Now you don't have to think about manually decrementing or handling $g_var, something else does that for you.

    Refactoring your solution may mean that you really need to write special operations that allow you to iterate over lists and handle certain internal values without the user of that object having to consciously know about them. I think in Perl there is a desire to try and solve a great many problems using language constructs and coding techniques when oftentimes the more obvious solution is to just push certain actions into functions or object methods instead. If you are doing Perl golf then disregard this post but your question doesn't read like that.

    Celebrate Intellectual Diversity

      Sure, something like Scope::Guard would do the trick as well, but these approaches can be a mighty big sledgehammer when you're trying to swat a misquito. Yes, they do work, but...

      I don't see anything wrong with using built in language constructs if they're not golf-like. I don't consider adding an extra block within the if clause to be golf-like, but I acknowledge that tastes do vary.

Re: at continue, last
by Anonymous Monk on Jun 06, 2014 at 08:11 UTC

    I don't get it

    while( ... ) { --$loop; ... }

    The repeated decrements are not DRY.

    DRY doesn't apply to match

Re: at continue, last
by LanX (Saint) on Jun 06, 2014 at 08:51 UTC
    I suppose there is more then one (disguised) goto otherwise nesting two if should do and is easily understood.

    But no matter how many exit-points you have, the entry-point is always the same. So why don't you decrement there after the first if ?

    Cheers Rolf

    (addicted to the Perl Programming Language)

      $loop is used in the conditional, so if I decremented it first, I'd have to add one to it everywhere it is being used.
        > $loop is used in the conditional, so if I decremented it first,...

        Unclear.

        None of your examples have $loop in the conditional and I suggested decrementing it after not before !

        Please explain what's different here

        if ( $condition1 ) { ... unless( $condition2 ) { ... } --$loop; # common exit point }

        Cheers Rolf

        (addicted to the Perl Programming Language)

        Whoops. Forgot to log in. The above comment is mine.
Re: at continue, last
by mr_mischief (Monsignor) on Jun 06, 2014 at 21:28 UTC

    Here's a completely different approach as a self-contained program for quick testing.

    ( The Getopt::Long::Configure isn't necessary here, but I personally use it whenever I'm using Getopt::Long as programs tend to grow to where I'd want it. )

    #!/usr/bin/perl use strict; use warnings; use Getopt::Long (); my %opt = ( 'do-stuff' => 0, 'do-more' => 0 ); Getopt::Long::Configure( 'gnu_getopt' ); Getopt::Long::GetOptions( \%opt, 'do-stuff+', 'do-more+' ); my $counter = 1; if ( $opt{ 'do-stuff' } ) { my @stuff_to_do = ( sub { print "some stuff\n"; } ); push @stuff_to_do, sub { print "some more stuff\n"; } if $opt{ 'do +-more' }; for my $s ( @stuff_to_do ) { $s->(); } $counter--; } print "$counter\n";
Re: at continue, last
by sundialsvc4 (Abbot) on Jun 06, 2014 at 12:06 UTC

    Agree ... this is the sort of code that I shudder to see, and see a lot.   Because of the way such code is constructed, it is difficult to “see” the conditions under which a particular bit of code might be executed.   Therefore, it is difficult to predict what conditions might actually prevail when a particular bit of (buggy) code is actually executing.   It is also difficult to locate all of the places where the value of a particular variable, such as $loop, is being manipulated, and to be certain that every single one of them is correct and that the entire set is complete.   When we harped at an entire generation of coders-to-be, “don’t use goto,” what I really think that we were trying to say is, “don’t be hard-to-follow or hard-to-predict.”

    Your comments are interesting, valid, and therefore, appreciated.   But when I encounter code like this, I usually have someone rewrite (“refactor” is the buzzword these days) the code and to write a bunch of tests to prove what it does, before and after.   And, if you look at such “monstrosities” long enough, you almost-inevitably find One More Bug™, or even, This Bug Is The Business Truth.™

Re: at continue, last
by RonW (Parson) on Jun 06, 2014 at 17:32 UTC

    Refining what InfiniteSilence said and applying to the OP examples, I'd go with:

    sub part0 { ... } sub part1 { ... } if ( $condition1 ) { { part0(); last if $condition2; part1(); } --$loop; }

    Then all of the condition and decrement logic is, visually, close together, so easier to understand.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://1088979]
Approved by boftx
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (7)
As of 2024-04-18 02:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found