News for hackers. Stuff that matters.
Re:Python 3.11: “Zero cost” exception handling by albertzeyer on Wednesday October 06, 2021 @11:25AM (#28774272)
> exceptions are a fundamental control-flow mechanism in Python

Where do you have this from?

In almost all Python code I have seen, exceptions are still for, as the name says, exceptions. So in the common cases, there would be no exceptions raised. I would assume that the exception handling code (under `except ...`) will be run only a tiny fraction of times compared to the other code, at least in most cases.

I would argue, if one abuses exceptions for any sort of control flow logic, this is bad design.

See also the list of builtin exceptions: https://docs.python.org/3/library/exceptions.html

From those, yes, there is StopIteration and StopAsyncIteration, which are used for control-flow, but the handling of those is anyway internal in CPython, and so the discussion about zero cost does not apply, as it would not change this (as far as I understand the current proposal).

Otherwise, all other exceptions are not used for control-flow.

Re:Python 3.11: “Zero cost” exception handling by BiteCode_dev on Wednesday October 06, 2021 @11:29AM (#28774327)
The for loop in python is a try/except catching StopIteration in a trench coat.

Also, EAFP, and the context manager protocol.

Re:Python 3.11: “Zero cost” exception handling by albertzeyer on Wednesday October 06, 2021 @02:55PM (#28776833)
But that is what I meant, this StopIteration would not be affected by the zero cost optimization. The zero cost optimization is about compiled Python bytecode and the VM interpreter. The StopIteration is handled internally by CPython (not via Python bytecode).

For example, consider this function:

    def foo():
        for i in range(3):
            print(i)
There is no try-except in this code, and neither in its bytecode. So this is not affected by the zero cost optimization from the linked issue.

The bytecode is this:

  2           0 LOAD_GLOBAL              0 (range)
              2 LOAD_CONST               1 (3)
              4 CALL_FUNCTION            1
              6 GET_ITER
        >>    8 FOR_ITER                12 (to 22)
             10 STORE_FAST               0 (i)

  3          12 LOAD_GLOBAL              1 (print)
             14 LOAD_FAST                0 (i)
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 JUMP_ABSOLUTE            8
        >>   22 LOAD_CONST               0 (None)
             24 RETURN_VALUE
The iteration logic is inside the `FOR_ITER` op. And that is purely handled inside CPython.

Also, this is again what I meant: In user code, you rarely would use custom exceptions for control flow. Please show me any example where you have seen otherwise.

So, again, what I wrote: I'm very confident that for most user code, the code path under `except ...:` is only rarely executed. Please show me any big Python project where this would not be the case. I doubt that there is any.

Also, btw, on EAFP, Guido van Rossum disagrees: https://mail.python.org/pipermail/python-dev/2014-March/1331...

Re:Python 3.11: “Zero cost” exception handling by fouric on Wednesday October 06, 2021 @02:10PM (#28776273)
> The for loop in python is a try/except catching StopIteration in a trench coat.

That's...horrifying, both from a computational efficiency perspective (due to the overhead of exceptions) and from a "beauty" perspective (exceptions are supposed to be exceptional, darn it!). Why is it implemented this way? Why not just use a normal loop and check a return value from the iterator?

Re:Python 3.11: “Zero cost” exception handling by Scramblejams on Wednesday October 06, 2021 @02:30PM (#28776512)
exceptions are supposed to be exceptional, darn it

This feeling is at odds with what is generally considered idiomatic Python, for better or worse.

Upthread BiteCode mentioned EAFP. See, for example: https://devblogs.microsoft.com/python/idiomatic-python-eafp-...

(It's certainly not unanimous. Guido himself is on the record as saying EAFP isn't better than LBYL, but in most of the Python I've cruised through these last umpteen years [that wasn't some other language written in Python], I've certainly seen an overall preference for EAFP. Naturally YMMV.)

Re:Python 3.11: “Zero cost” exception handling by fouric on Wednesday October 06, 2021 @05:45PM (#28778897)
I think that implies that either "exceptions" are misnamed in Python (as in every other language with that name, they're meant to be exactly that - exceptional - so whatever Python calls "exceptions" isn't the same as in other languages), or that that particular idiom is wrong, and needs to be rethought.
Re:Python 3.11: “Zero cost” exception handling by dragonwriter on Wednesday October 06, 2021 @02:14PM (#28776315)
> Why not just use a normal loop and check a return value from the iterator?

Because an iterator needs to be able to return any python value, and if you did that, there would be at least one python value that an iterator could not actually return.

Unless you required the iterator to wrap real return values in a container (basically, an optional/maybe monad) but then you have unwrapping overhead on every real return value, which is worse.

Re:Python 3.11: “Zero cost” exception handling by fouric on Wednesday October 06, 2021 @05:49PM (#28778939)
Couldn't the runtime just allocate a specific Python object representing the case where the iterator is complete? Make that object implementation-specific, hide it as best as you can, write documentation stating that users should not use this value directly, and if they do - they voided the warranty, and should expect evil to befall them. (ultimately, you can't prevent the user from doing really dumb things e.g. editing the Python binary directly)
Re:Python 3.11: “Zero cost” exception handling by dragonwriter on Wednesday October 06, 2021 @06:00PM (#28779042)
You do that with one thing, okay, maybe it works.

You do that with two or more of the protocols that Python has that use return values for return values ans exceptions for flow control signals and...you make it a lot harder to work with them, especially in conjunction.

Re:Python 3.11: “Zero cost” exception handling by fouric on Thursday October 07, 2021 @10:41AM (#28786902)
Can you give an example of this? I can't think of any myself - generators also raise a StopIteration exception, for instance, so they could use the same value.
Re:Python 3.11: “Zero cost” exception handling by carapace on Wednesday October 06, 2021 @12:34PM (#28775096)
In Python e.g. instead of doing this:

    if key in some_dict:
        foo = some_dict[key]
        ... # A
    else:
        ... # B
you would do this:

    try:
        foo = some_dict[key]
    except KeyError:
        ... # B
    else:
        ... # A
Re:Python 3.11: “Zero cost” exception handling by albertzeyer on Wednesday October 06, 2021 @02:57PM (#28776863)
You can do that, but:

- Even in this example, I would assume that branch A is more often executed. So the zero cost optimization (which is about branch A) would improve this code performance.

- I would argue, code which uses `some_dict.get(key, fallback)` or explicitly check `if key in some_dict: ...` is both more clean and more Pythonic. See also e.g.: https://mail.python.org/pipermail/python-dev/2014-March/1331...