Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Re (tilly) 6: Fear of Large Languages (was: "Would you use goto")

by tilly (Archbishop)
on Dec 07, 2001 at 02:58 UTC ( #130100=note: print w/replies, xml ) Need Help??

in reply to Re: Re (tilly) 4: Fear of Large Languages (was: "Would you use goto")
in thread Would you use 'goto' here?

foreach my $foo (@bars) { { if ($foo =~ /baz/i) { last unless $foo eq uc $foo; } else { last unless $foo ne uc $foo; } # stuff } do_more_stuff($foo); }
works just fine. There are several other options as well. First there is the continue that you mentioned:
foreach my $foo (@foos) { if ($foo =~ /baz/i) { next unless $foo eq uc $foo; } else { next unless $foo ne uc $foo; } # stuff } continue { do_more_stuff($foo); }
and then (depending on what you do in the if statement) there is reversing the order of your operations:
foreach my $foo (@foos) { do_more_stuff($foo); if ($foo =~ /baz/i) { next unless $foo eq uc $foo; } else { next unless $foo ne uc $foo; } # stuff }
You can have the chain of ifs be replaced by a function call that returns from multiple points:
foreach my $foo (@foos) { do_stuff($foo); do_more_stuff($foo); } sub do_stuff { my $foo = shift; if ($foo =~ /baz/i) { return unless $foo eq uc $foo; } else { return unless $foo ne uc $foo; } # stuff }
And so on.

I have, in fact, used every one of these solutions except the goto one, and I prefer all of them to the goto solution. Why? Because I find each of them clearer, they allow me to see program flow in terms of following blocks. The goto forces me to see an element of program flow which is not some form of block. I don't like that. Furthermore, no matter how clearly the goto solution's intention may be, its use opens up the possibility of traps like this:

foreach (1..5) { print "Hello\n"; goto DONE; } DONE: foreach (1..5) { print "World\n"; goto DONE; } DONE:
By contrast anything only relying on return and loop control statements can be much more easily verified correct based on local examination. (OK, in this case your goto construct is verifiably correct without looking at outside code. But it will take more time for most people to figure out why the one is verifiably OK while the other is demonstrably bad than it will to figure out my alternate solution.)

Again, this is not something I would use a goto for.

Fixed a thinko danger pointed out to me. last and next are not the same.

Replies are listed 'Best First'.
(dragonchild) 8: Fear of Large Languages (was: "Would you use goto")
by dragonchild (Archbishop) on Dec 07, 2001 at 18:46 UTC
    As I said earlier in the thread, continue block or function call should have been what I did. But, I felt that I didn't want to hide the meat of the script in a function call and continue blocks are "a lesser-known" feature of Perl, similar to "goto &SUB".

    I guess my point is that I have a reason for not wanting to do either of the "correct" ways, and one of those reasons is the very reason most people gave Ovid to not use "goto &SUB", even though it was the absolute correct syntax to use in his specific case.

    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      I guess my point is that I have a reason for not wanting to do either of the "correct" ways

      The general 'better known' vs 'lesser known' argument can be summarized as: if X is a problem can be solved with either construct A or B, and if A is assumed to be more widely known, then we should choose to implement using A. A reasonably fair argument. Counter examples obviously would occur when say memory or speed is crucial and B is clearly optimal with regard to these additional constraints. But we are talking about readability optimization here right?

      However, I argue that this does not apply to using goto rather than continue (even if goto is indeed more known than continue). Why? Because familiarity with goto LABEL doesn't really help the reader understand the logical structure of the code.

      The logical elements of the code should be mirrored in the structural elements of the code as much as possible. This means jump destinations should mesh with the boundaries of the structural elements (block boundaries), and things like next, last, and redo do so. Using goto DONE introduces a synthetic, non-structural element to delimit a logical element of the code. This places an additional mental burden on the reader who now must maintain a dangling mental reference to a goto-label because the code structure itself provides no cue about the limits of the current logical element.

      Thus while using goto may relieve your readers of having to look up continue or to learn about bare-blocks and loop control statements (as per one of tilly's suggestions), it doesn't relieve them of the mental burden of understanding the logical usage of the goto in the current code.

      As an aside, another alternative for the particular code example you gave would be to use the ?: operator and avoid having both an 'if' and an 'else' block:

      for my $foo (@bars) { # ... do preliminary stuff # ... if ($foo =~ /baz/i ? $foo eq uc $foo: $foo ne uc $foo) { # ... do conditional stuff # ... } # ... do remaining stuff # ... }

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://130100]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2021-09-28 16:10 GMT
Find Nodes?
    Voting Booth?

    No recent polls found