Invoking return through a function?

Steve D'Aprano steve+python at pearwood.info
Sun Oct 29 20:42:31 EDT 2017


On Mon, 30 Oct 2017 03:35 am, Alberto Riva wrote:

> On 10/29/2017 10:35 AM, Steve D'Aprano wrote:

[...]
>> You mean *less* explicit. "checkKey" gives absolutely no hint that it
>> causes the current function to return.
> 
> That's just because I used a name that was too generic in my example. I
> can call it "returnIfKeyMissing", and then it would be clear.

No it wouldn't. That sounds like it is the "returnIfKeyMissing" function that
returns if the key is missing, and presumably pauses forever, never
returning, if the key exists.

Of course we can *learn* that this is not the case, by reading the docs (if it
has any) or the source code (if it is available). But what of every other
function, any one of which might have been named like your first example:

    checkKey

We cannot rely on naming conventions, because people won't always follow it.
*Any* function could potentially return early from the caller.

But honestly, if you're prepared to write:

    returnIfKeyMissing(dict, key)

that's LONGER than:

    if key not in dict: return

Since your motive appears to be the wish to save typing at the expense of
readability and maintainability, then I expect that *in practice* you
wouldn't use "returnIfKeyMissing" but would prefer a less explicit, shorter
name like "checkKey".


[...]
>> You really should re-think your strategy. Your suggestion, if possible,
>> would lead to difficult to maintain code where you couldn't easily tell
>> where the exit points of a function where.
> 
> But again, it's just a naming problem. 

It *really isn't* a naming problem. Being able to force the caller to return
is a kind of GOTO, and it violates both the letter and the spirit of the
principle that functions should have "one entry, one exit".

Of course we already violate the second part of that, by allowing multiple
returns. But that doesn't mean that any other violation should be acceptable.

Allowing functions to force their caller to exit allows them to violate the
caller's post-condition contracts.

But even if it were just a naming problem, you under-estimate its magnitude.
The word "just" is not justified here: even treated as a naming problem, it
is a big problem. Not an end-of-the-world problem, but still big enough.


> Something like returnIfKeyMissing 
> would make it easy to tell where the exit points are.

No it wouldn't, because not everyone is going to use such a clumsy, long
naming convention, either out of ignorance or for some other reason. Maybe
you're using a library where everything is named in Dutch, or Russian. Maybe
the function was named "foo()" long ago, and has only subsequently gained the
ability to force the caller to return but the name was never changed.


> And as Bartc 
> pointed out, we already have this situation with exceptions, so it would
> be nothing new.

Pardon me, but it was *me* who pointed out the analogy with exceptions, not
Bart. But this is different from an exception.

The similarity is quite weak:

- any function can raise an exception;

- your hoped for feature would allow any function to cause the 
  caller to return;

But the differences are profound:

- exceptions are an alternative to normal execution flow, they don't
  silently continue unless explicitly caught and silenced;

- if you don't explicitly catch the exception, it is obvious when 
  one occurs, because your program halts and you get an obvious 
  stacktrace;

- your suggested force-caller-to-return would silently alter the
  control flow of the caller, without warning or signal that it
  had happened.

That's a very significant difference.



> Indeed, what I'm asking for could be accomplished by 
> wrapping the body of each function in a try/catch block for an ad-hoc
> exception type.

A terrible idea. Why not just write a "validate input" function that checks
your input and returns True for valid and False for invalid, then:

    if not valid(args):
        return

That's little harder to type than

    returnIfNotValid(args)

and much more comprehensible.


> But again, since the language doesn't have macros

And this is the sort of misfeature why Guido is dead-set against Python ever
getting them.

Yes, we get it that Lisp macros are really, really powerful. But there are two
bottle-necks in coding:

- writing the code in the first place;

- maintaining the code afterwards.

Macros are aimed at simplifying the first, at the cost of the second. That's
not a strategy Python follows.



-- 
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