On Thu, Oct 31, 2019 at 02:47:35PM +0100, Andrew Barnert wrote:
> On Oct 31, 2019, at 13:56, Steven D'Aprano <st...@pearwood.info> wrote:
> > 
> > I disagree. I think it's a pretty small breaking change,
> 
> From my test earlier on the thread, using a function to raise makes a 
> function that does nothing but raise and handle an exception take more 
> than twice as long. Which implies that the actual raise part (not 
> counting the outer function call, handling the exception, and 
> returning) is far more than twice as long.

I don't recall seeing your test code, but I don't follow your reasoning 
here. Unless you are using a custom Python build where the raise 
statement has been replaced by a raise function, I don't see how you can 
conclude that the raise statement inside a function takes "far more than 
twice as long" as a bare raise statement.

Making raise a function will add the overhead of a function call, which 
by my tests is smaller than the cost of a raise and catch:

    $ ./python -m timeit "try: raise ValueError
    > except ValueError: pass"
    100000 loops, best of 5: 3.26 usec per loop

    $ ./python -m timeit -s "def throw(): raise ValueError" "try: throw()
    > except ValueError: pass"
    50000 loops, best of 5: 5.44 usec per loop

YMMV.

So on my machine, raise-in-a-function is about 70% slower than raise, 
not 100% or more. That's a pure-Python function. It's possible that a 
builtin function in C will have less overhead.

But to paraphrase the prevailing opinion expressed in the "word list" 
thread, you cannot possibly be seriously worried about a few micro- 
seconds difference. (Only slightly serious.)

In this case, I'm not that worried about micro-benchmarks unless they 
can be shown to add up to a significant performance degradation in 
macro-benchmarks too. The cost of catching exceptions is, as I 
understand it, quite a bit more expensive than actually throwing them. 
We can't throw lots of exceptions without a corresponding catch, so I 
expect that any additional overhead from a function call will probably 
be lost in the noise of the catch.

But if that's not the case, then "performance" may end up being a good 
reason to reject this proposal.


> Also, there are many places in the Python data model where you have to 
> raise an exception, such as StopIteration;

Does the Python data model not have function calls? *wink*


> And what’s the advantage?
> 
> If we need raise inside an expression without extra overhead, this 
> doesn’t solve the problem; we’d need a raise expression (similar to 
> the yield expression), not a raise function. 

Yield expressions are a red herring here. Yield expressions are a weird 
syntactic form that allow you to feed data into a running generator. 
raise doesn't need to do that. The raise function will never return, so 
it doesn't need to return a value. It will be kind of like os._exit, and 
sys.exit.


> If we don’t care about the overhead, there is no problem to solve; you 
> can already get this behavior with a one-liner. If that’s still too 
> inconvenient or undiscoverable, we can add the one-liner to builtins 
> without removing the statement at the same time. So, what’s the 
> benefit of removing the statement?

"Only One Way To Do It" *wink*

We could have added a print_ function and kept the print statement too. 
And for years, people wrote their own one-liner print_ functions. (I 
have lost count of the number of times I did.) If your argument was 
compelling, we never would have changed print and exec to functions.

But we did. The "just use a one-liner" argument isn't very strong. It's 
a work-around for the missing functionality, not a positive argument in 
favour of the status quo.

If, back in the early days of Python, Guido had made raise a function, 
we'd all accept it as normal and desirable. I doubt anyone would say "I 
really wish it was impossible to call raise from an expression without 
having to write an unnecessary boilerplate wrapper function".

As I said above, I'll grant you the *possibility* that performance may 
tilt the balance, but honestly, I see no other reason why we should 
prefer a *less flexible, less useful* raise statement over a more 
flexible, more useful function. Especially if a built-in function 
written in C can avoid most of the pure-Python function call overhead, 
narrowing the performance gap.


-- 
Steven
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/AJTPDZTODJW34VYCRDEXHUMSG4BYMCQ2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to