Invoking return through a function?

Steve D'Aprano steve+python at pearwood.info
Mon Oct 30 23:00:25 EDT 2017


On Tue, 31 Oct 2017 01:06 pm, Alberto Riva wrote:

> On 10/30/2017 10:27 AM, Rhodri James wrote:
[...]
>> You can do the same in C.  I've had the displeasure of trying to
>> maintain such code.  It was near-unreadable, because it constantly broke
>> your expectations of what the code flow *could* be.  The fact that
>> something that could return from the middle of your function without the
>> slightest indication was a rich source of bugs.
> 
> Just curious: how is this different from calling a function that throws
> an exception (that may or may not be caught by some other function
> higher up in the call stack)? That also breaks your expectations of what
> the code flow would be...

The mere possibility of an exceptions does not break the normal, unexceptional
code flow. You can still reason about the flow "if the data is valid, and
there are no exceptions" where execution proceeds from the top of the
function down, only exiting if there's a return. That's your base,
unexceptional case, and there's no traps there. Any jump (return, break,
continue) is explicit and obvious.

Then you can think about the exceptional case, where data is invalid and you
get an exception, separately. They're independent.

In the exceptional case, the control flow is different, but still predictable:
an exception is raised, and control exits the current block, to be either
caught by the nearest surrounding except block, or if no such block, halting
execution. Either way, its all relatively[1] straight-forward, with no
surprises. You can't jump into the middle of a function, you can only pop out
of the current call-chain into the surrounding function call.

But with macros, you can't do that. Anything can be anything. An ordinary
looking function call inside a loop might mask a hidden `continue` or
`break`. A function call might mask a secret `return`.

Python has no GOTO, fortunately, but C has at least two, GOTO and LONGJMP. A C
macro could, if I understand correctly, jump into the middle of another
function. (Yay for spaghetti code!)

I suppose it wouldn't be too awful if macros required dedicated syntax, so at
least you could distinguish between "this is a safe, ordinary function"
and "this is a macro, it could mean anything". But it would still increase
the maintenance burden, proportional to the number of macros used.


> To clarify, I agree with your concern. What I mean is that even in
> normal conditions there's never any guarantee that the code flow is what
> you expect it to be just by reading the body of a function.

True -- there's always *two* possible paths: the standard, unexceptional
control flow, when no exceptions are raised; and the exceptional control
flow. The second is more complex than the first, but in *practice* (if not in
theory) we can at least be reasonably sure of what exception is raised and
where it is caught.



[1] There's no doubt that exception handling, except in the simplest forms, is
more complex than code without exception handling. And this is why Rob Pike
designed Go without exceptions.


-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list