-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mandatory error handling #5
Comments
This is not forward compatible. The best we could do is mark that a failure result is unlikely, which might influence branch prediction or code layout, but we can't have the compiler omit error handling completely. Otherwise when we add an error condition in the future, existing compiled modules will have no choice but to crash. |
Yup, that would only be for extensions that need to be recompiled for every Python version. I expect there will still be a fair number of those, as you can get more performance that way. |
In that case, #7 😄 |
So far, many functions were deprecated with Also, only a minority of functions will be deprecated one day, the majority will stay. I would prefer to not have to pay a tax "just in case" tomorrow we might consider to deprecate a function. I'm fine with treating deprecating as build errors when the function is removed. It may be even better since runtime errors may not be catched by tests, but may only happen on production. The Macro to hide deprecated functions proposes a solution for that which doesn't require to check every single call for any C API function when writing a C extension. Well, in general, functions can already fail for multiple others reasons, so there is no need to "enforce" callers to check for errors, it's already part of the obvious API. I created the opposite of this issue: Functions which cannot fail. IMO we need exceptions for some specific functions which cannot fail. Otherwise, the API will be way less pleasant to use. |
Sure, but we haven't removed anything from the limited API yet.
A minority of functions can not fail, just like in a minority of functions it's safe to return a borrowed reference. |
Before mandating that all C API functions should be able to return an error, you should think about developer ergonomics. What does it mean to have to check errors for every possible CPython C API function call? Code using the C API will be even more verbose than it is today. While it's true that more and more users will rely on higher-level wrappers such as Cython or nanobind, this shouldn't be a reason to make the C API harder to use. As for the idea that deprecated C functions should emit a runtime warning, that's not how deprecation usually works in C/C++. It will also be funny to get a deprecation warning without the corresponding source code displayed in the traceback (because tracebacks don't include C functions). Overall, API design should remain pragmatic, not dogmatic. There is no reason to check for errors after If you're not convinced, look at modern APIs in other languages with explicit error handling (the Rust stdlib, for example). You'll see that errors are returned only where semantically required, not as a provision for "errors that we might want to return in the future". |
That makes sense, but it's hard to draw a consistent line. Or rather, it's quite easy now! All exceptions should be approved by the C API WG. We can collect the exceptions to the rule, and reorganize when keeping the list of exceptions becomes unwieldy.
“Harder to use” is relative: is it more typing, or more details to remember? So here's another reason for this guideline: making the API more regular, so that a reviewer doesn't need to open the docs for every function a piece of code calls. Ideally there'd be a single answer for questions like “Should there be error handling?” and “What value signals an error?”. So, IMO,
They make it very hard to omit error checking when it's needed. That makes for a very different story. |
That sounds reasonable to me.
Good point :-)
I agree with reserving
Admittedly... I was going to say that you can use |
We don't like that API, see problem number one (and especially Mark's comment). If they were added today, they should take output arguments ( |
I suppose that Antoine means here that some existing API can return -1 which is a valid value, and doesn't report an error.
For me, it means "having to write more lines of code". Example with a function which requires to check for errors (worst case, PyLong API): - i = PyLong_AS_LONG(v);
+ Py_ssize_t i = PyLong_AsSsize_t(v);
+ if (i == -1 && PyErr_Occurred()) {
+ Py_DECREF(tuple);
+ return NULL;
+ } 1 line vs 5 lines. Here, the code is correct, error must be checked. But it's just to show how an API which requires to check for error requires 5x more lines of code for a single function call. |
Time for a controversial opinion! - i = PyLong_AS_LONG(v);
+ Py_ssize_t i = PyLong_AsSsize_t(v);
+ if (i == -1 && PyErr_Occurred()) goto error; I find the one-line |
That sounds like a good step forward. Maybe we can start by adding the attribute to functions added to Python 3.13 which can fail. |
Or perhaps add it to all functions returning an error and see how many projects break :-) |
By the way it seems like MSVC has sophisticated annotations to let the compiler understand a function call's semantics: |
The
Oh, that's nice! |
Yeah, and they're fantastic. But not portable and very invasive in definitions, so I've always just assumed that until gcc ended up with something similar (i.e. we can use the same macros with different definitions) it'd never go anywhere. |
Well, you'd certainly end up writing abstraction macros. gcc would never use the same syntax as MSVC, would it? :-) |
Of course there'd be macros, but there'd also be significant pushback about macros on literally every parameter that don't do anything on gcc. I'm not going to fight that battle. |
All new functions must be able to signal failure.
Users should write error handles after every API call.
This is needed for run-time deprecation warnings:
DeprecationWarning
with-Wall
raises. So, any function might raise in the future. (Deprecating infallible function, via compiler warning, requires users to recompile.)For functions whose current implementation never raises, we should find ways to instruct the compiler to skip users' error handling code.
The text was updated successfully, but these errors were encountered: