Python-list Digest, Vol 169, Issue 23

ROGER GRAYDON CHRISTMAN dvl at psu.edu
Thu Oct 12 11:53:40 EDT 2017


On Thu, Oct 12, 2017 08:05 AM, Steve D'Aprano wrote:>
On Wed, 11 Oct 2017 10:57 pm, Stefan Ram wrote:
>
>>  FWIW, in is book "Touch of Class" (2009) Bertrand
>Meyer writes:
>> 
>> |Such instructions are just the old goto in sheep's clothing.
>> |Treat them the same way as the original:
>> |
>> |/Touch of Methodology/:
>> | Sticking to one-entry, one-exit building blocks
>> |Stay away from any "break" or similar control mechanism.
>
>I have a great deal of respect for Meyer, but in this case I think he has it
>badly wrong on both counts (`break` and "one-entry,
>one-exit").
>
>Unrestricted GOTO (as in BASIC, circa 1970, where you could jump to any
>line
>in the code, or as in assembly) is rightly considered harmful (albeit
>necessary in assembly). But if Meyer means *any* sort of jump
>("similar
>control mechanism"), then that would rule out not just `break` and
>`continue`
>but also:
>
>    * while loops
>    * for loops
>    * if...else
>    * case/switch statements
>    * calling subroutines (functions or procedures)
>    * exception handling
>
>Remember that a function call is basically a GOTO in disguise: execution jumps
>to the function, and jumps back when the function returns. In BASIC, there
>was a GOSUB intermediate between a GOTO and a procedure call.
>
>Surely Meyer doesn't mean to say we should never call functions or use
>`while`, `for` or `if`. So he has to distinguish between kinds of jumps:
>
>Good jumps (I presume):
>
>    * function calls
>    * if...else
>    * looping
>
>Evil jumps:
>
>    * unrestricted BASIC-style GOTO/GOSUB any line number
>    * break/continue
>
>Not sure:
>
>    * GOTO where there are restrictions on where you can jump
>    * COMEFROM
>
>(I kid: I'm sure Meyer would oppose COMEFROM, and I expect that even
>Pascal-style restricted GOTO would be on his "evil" list to
>avoid.)

This seems like a veritable straw man if any.
I am fairly sure that "one entry, one exit"
does not precisely mean "no branching whatsoever"
Nor does discouraging unrestricted GOTO
suggest that either.

Clearly a while or for loop without break i
is single-entry and single exit.
The if-else has a clear single entry at the test condition,
and a single exit could be imagined at the program
point immediately after the if-else., etc.

The case/switch does have a single exit in the same
way as the if.   Unfortunately, it does in itself sort of
violate the single entry idea when a break does not
precede the next case.
That just leaves the multiple returns in a functionand the exception handling.
>So the question becomes, why are such harmless, simple to understand,

innocuous jumps like `break` and `continue` in the evil list, when they not

only simplify code but make it more efficient?


# with break

for i in range(2**64):
    if isprime(i):
        print(i, "is prime")
        break


# without break
still_searching = True
for i in range(2**64):
    if still_searching and isprime(i):
        print(i, "is prime")
        still_searching = False

# without break, attempt number 2
still_searching = True
i = 0
while still_searching and i < 2**64:
    if isprime(i):
        print(i, "is prime")
        still_searching = False


# without break, the way it should be:
i = 0
while not isprime(i):
... i = i+1
print(i, "is prime")

I believe this is far simpler _and_ more efifcient than
any of your answers above.   

Do you really believe that there are no prime numbers
less than 2**64?   Can you imagine any circumstance
when "i < 2**75" would become false in this application?
Can you really claim that a solution is more efficient
when it repeatedly tests a condition that can never
posslbly be false?

That is the biggest objection programming teachers

like me dislike the break statement -- it leads to very
careless programming.   Once you imagine that you will
use a break to exit your loops, you might stop thinking
about what your loop conditions are.  And then you find
yourself in a corner where the only way out is to break.

It's like:  I know that I can always call a tow truck
whenever my car runs out of gas on the highway,
so I'll no longer bother checking or filling my tank.
I'll just drive until I'm beyohd fumes, break down,
call a tow, and then tell my boss how I was unavoidably
late because I broke down on the highway.

Ironically, after telling us to stick to code with one entry and one exit,
Meyer then contradicts himself by recommending exceptions:

> |You can use exception handling as a technique of last resort
> |to handle unexpected events for which the normal control
> |structures let you down.

Even more ironically, exception handling is most similar to a COMEFROM, which
was invented as a joke.

The exception handler itself has one entry (the exception)
and one exit.  And, unlike goto's and set_jmp()
is easiliy incorporated into other control structures
depending on where you want to go after any recovery steps.

The code that generated the exception, of course, seemingly
has more than one exit, but exceptions are just that --
exceptions.   I hope you don't start using counting loops
up to 2**64 to visit a 100 element array and rely on
IndexError to exit such a loop.

Roger Christman
Pennsylvania State University



More information about the Python-list mailing list