in reply to Wait and retry loop without goto

Not only can you use a while loop but you can also use goto in a better way. Perl has two distinct forms of goto. The first (as you are doing here) is a classic goto. Just a jump, all state preserved, messy. Don't do it.

The second is a tail call form. If you goto &sub it leaves the current stack frame and re-enters with the existing values of @_ re-aliased. This means you have clean scope. This is very useful for retries. So in this case we could:

for my $router (@routers) { get_config($router, 0); } .... sub get_config { my ($router, $retries) = @_; my $output = `expect -f show_running_config.exp $router->[$IP]`; die "Failed to get config for $router->[$NAME] at $router->[ +$IP]: $output\n" if $retries > 3 and $?; unless ($?) { sleep 5; $_[2] = $_[2] + 1; goto &get_config; return write_config($output, "$router->[$NAME].cfg"); }

Here goto gives you an effective restart condition, but with a clean state (i.e. all locally scoped variables, such as $output get cleared on each retry. It is very nice in the sense it gives you a clean restart on the function without the extra stack overhead (though since you are only retrying 5 times, recursion may be another option).

Replies are listed 'Best First'.
Re^2: Wait and retry loop without goto
by Laurent_R (Canon) on May 15, 2015 at 06:30 UTC
    Hmmm. I guess this probably works well, but this form of goto is somewhat magical, I am not sure it should be advised to someone probably not understanding the details and, more broadly, for such a simple task, where a while loop or a simple recursive call would do as well.

    Je suis Charlie.
      I think it seems magical because it isn't really a goto. I see why Perl 6 is changing it to &sub.nextwith(). It would be nicer IMO if it had been given its own keyword like tailcall().
        IMHO, it is a form of goto in the sense that the code never returns from that call. The Camel book says the following on this form of goto:
        The goto &NAME form is highly magical and sufficiently removed from the ordinary goto to exempt its users from the opprobrium to which goto users are customarily subjected. It substitutes a call to the named subroutine for the currently running subroutine.

        Having said that, in his book Modern Perl, chromatic also suggest to use a goto to eliminate tail-recursion:

        Perl does not eliminate tail calls automatically, but you can get the same effect by using a special form of the goto builtin. Unlike the form which often produces spaghetti code Named because control flow is as simple and straightforward as a plate of spaghetti., the goto function form replaces the current function call with a call to another function. You may use a function by name or by reference. You can even modify the arguments passed to the replacement function by modifying @_:
        # split the array down and recurse if ($item < $miditem) { @_ = ($item, @array[0 .. $midpoint]); goto &elem_exists; } # split the array up and recurse else { @_ = ($item, @array[$midpoint + 1 .. $#array] ); goto &elem_exists; }
        Sometimes optimizations are ugly, but if the alternative is highly recursive code which runs out of memory, embrace the ugly and rejoice in the practical.

        So, you are right, may be it should have been called something like tailcall(), except that the goto &NAME form can also be used for other things than tail reduction elimination.

        Je suis Charlie.