GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Improve C API guidelines for return values by erlend-aasland · Pull Request #1129 · python/devguide

Conversation

@erlend-aasland

@erlend-aasland erlend-aasland commented Jun 26, 2023 •
edited by github-actions Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Clarify that returning an error indicator should be done iff an
exception is raised.

For functions returning an int, a negative value should be returned.
Suggest -1 unless there is a need to distinguish between error types.


📚 Documentation preview 📚: https://cpython-devguide--1129.org.readthedocs.build/

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@erlend-aasland
Improve C API guidelines for return values
ba7ce7b
Clarify that returning an error indicator should be done iff an
exception is raised.

For functions returning an int, a _negative value_ should be returned.
Suggest -1 unless there is a need to distinguish between error types.
@erlend-aasland
erlend-aasland requested review from encukou, markshannon and vstinner June 26, 2023 18:59
@erlend-aasland erlend-aasland linked an issue Jun 26, 2023 that may be closed by this pull request
Document the preferred style for API functions with three, four or five-way returns #1121
Closed
@erlend-aasland
Commas
d45cfd1
@erlend-aasland erlend-aasland mentioned this pull request Jul 11, 2023
gh-106307: Add PyMapping_GetOptionalItem() python/cpython#106308
Merged
@erlend-aasland

erlend-aasland commented Aug 27, 2023

Copy link
Copy Markdown
Contributor Author

@encukou, are you ok with this change?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner
vstinner approved these changes Aug 27, 2023
View reviewed changes

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

erlend-aasland reacted with hooray emoji
All reactions
  • 🎉 1 reaction
AA-Turner
AA-Turner reviewed Aug 28, 2023
View reviewed changes
Comment thread developer-workflow/c-api.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread developer-workflow/c-api.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland @AA-Turner
Apply suggestions from code review
01335f5
Co-authored-by: Adam Turner <[email protected]>
@erlend-aasland

erlend-aasland commented Aug 28, 2023

Copy link
Copy Markdown
Contributor Author

Thanks, Victor and Adam.

AA-Turner reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 28, 2023

Copy link
Copy Markdown
Member

Sadly, the newly added PyLong_AsInt() doesn't respect new guidelines, but it was a deliberate choice. I like the new PyDict_GetItemRef() API, it's pleasant to use it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

encukou
encukou reviewed Aug 31, 2023
View reviewed changes
Comment thread developer-workflow/c-api.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Aug 31, 2023

Copy link
Copy Markdown
Member

Well, I've thought about this, and realized I haven't seen an actual use case for distinguishing between error types. Is there one?
It seems that if an “error” is expected, like with “missing dict key”, that should be handled as another “success” (positive return value), so we don't need to allocate/init an exception object.
That leaves negative return values for “unexpected” errors, where the function can't really distinguish.

I'd love to see a counterexample :)

the newly added PyLong_AsInt() doesn't respect new guidelines

Well, it doesn't respect the old guidelines either, so that's unrelated to this PR :)

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Aug 31, 2023

Copy link
Copy Markdown
Member

Well, I've thought about this, and realized I haven't seen an actual use case for distinguishing between error types. Is there one?

It's not common to report different error cases, but it happens, especially if the API does not raise an exception.

On error, Py_DecodeLocale() sets size to (size_t)-1 on memory allocation failure and (size_t)-2 on decoding error.

_Py_DecodeLocaleEx() has 3 error cases:

  • return -1: memory allocation failure
  • return -2: decoding error
  • return -3: unsupported error handler

For the caller, it's important to be able to distinguish the different errors. Extract of unicode_decode_locale():

    int res = _Py_DecodeLocaleEx(str, &wstr, &wlen, &reason,
                                 current_locale, errors);
    if (res != 0) {
        if (res == -2) {
            PyObject *exc;
            exc = PyObject_CallFunction(PyExc_UnicodeDecodeError, "sy#nns",
                                        "locale", str, len,
                                        (Py_ssize_t)wlen,
                                        (Py_ssize_t)(wlen + 1),
                                        reason);
            if (exc != NULL) {
                PyCodec_StrictErrors(exc);
                Py_DECREF(exc);
            }
        }
        else if (res == -3) {
            PyErr_SetString(PyExc_ValueError, "unsupported error handler");
        }
        else {
            PyErr_NoMemory();
        }
        return NULL;
    }
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland @encukou
Update developer-workflow/c-api.rst
b045b03
Co-authored-by: Petr Viktorin <[email protected]>
@erlend-aasland

erlend-aasland commented Aug 31, 2023

Copy link
Copy Markdown
Contributor Author

Well, I've thought about this, and realized I haven't seen an actual use case for distinguishing between error types. Is there one?

I'd prefer if the guideline simply said "return -1 on error"; after all a guideline is meant for the general case, not the special case. For the extraordinary cases, it is ok to not follow the general guideline (after a discussion, of course).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

erlend-aasland
erlend-aasland commented Aug 31, 2023
View reviewed changes
Comment thread developer-workflow/c-api.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Sep 4, 2023

Copy link
Copy Markdown
Member

It's not common to report different error cases, but it happens, especially if the API does not raise an exception.

Well, if an exception isn't raised, then the function should not return a negative value (or NULL) at all.
That's the main consistency win we're going for: you should be able to tell whether an exception was raised from the return value alone.


There are two parts of the question of “Does a negative value other than -1 signal that an exception was raised?”

  • what should functions return? (we can say -1 only for now, it's easy to allow more values later)
  • what should callers check for, == -1 or < 0? (on this we can't really change our minds later)
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Sep 4, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There are two parts of the question of “Does a negative value other than -1 signal that an exception was raised?”

  • what should functions return? (we can say -1 only for now, it's easy to allow more values later)
  • what should callers check for, == -1 or < 0? (on this we can't really change our minds later)

I would prefer callers to check for < 0 (any negative value implies an exception was raised). For C API implementers, I'd prefer simply to suggest using the return value is -1 (we're only talking about int returns here) if an exception is raised. If it makes it easier to formulate this, I'm fine with simply saying "return a negative value" instead of "return -1".

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Sep 4, 2023

Copy link
Copy Markdown
Member

Yeah, return -1 and if (... < 0) is probably the best solution. It means all the negative return values except -1 probably can't be repurposed for anything useful in the future, but that's probably OK.

But perhaps this shouldn't be decided in an issue, especially since there'll be lots of API discussions at the sprint in about a month.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Sep 4, 2023

Copy link
Copy Markdown
Contributor Author

But perhaps this shouldn't be decided in an issue, especially since there'll be lots of API discussions at the sprint in about a month.

Well, this PR has been up for two months already; there's no harm in waiting another month :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Sep 4, 2023

Copy link
Copy Markdown
Member

Even when I'm 100% sure that a function can only return -1 on error, I prefer to write if (func() < 0). For me, it's a way to say: "if the function fails".

In the C library, it's unclear if a function returns 0 or 1 on success. It depends. But in the Python C API, it's likely that a function returns "a negative number" on error.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland

erlend-aasland commented Sep 5, 2023

Copy link
Copy Markdown
Contributor Author

Even when I'm 100% sure that a function can only return -1 on error, I prefer to write if (func() < 0). For me, it's a way to say: "if the function fails".

Yeah, that's the C idiom, so that would be my preferred style.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Sep 5, 2023

Copy link
Copy Markdown
Member

If a function can raise an exeeption, I don't see the point of having more than one negative value. The exception should contain the details: exception type and exception message.

In the worst case, if a very important additonal information cannot be passed in the exception, i would prefer to add a separated argument, than break the rule: return 1, 0 or -1.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Sep 5, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

My Py_DecodeLocale() example is unrelated: it doesn't raise an exception, and so uses a different API. I'm talking about public C API which raise exceptions.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland
Update developer-workflow/c-api.rst
95b5951
vstinner
vstinner reviewed Sep 6, 2023
View reviewed changes
Comment thread developer-workflow/c-api.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland @vstinner
Update developer-workflow/c-api.rst
8049811
Co-authored-by: Victor Stinner <[email protected]>
@willingc willingc added the DO-NOT-MERGE Do not merge this PR label Oct 10, 2023
@erlend-aasland

erlend-aasland commented Oct 11, 2023

Copy link
Copy Markdown
Contributor Author

I'll leave this for the C API workgroup.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@erlend-aasland erlend-aasland closed this Oct 11, 2023
@erlend-aasland
erlend-aasland deleted the c-api-guidelines/clarify-return-values branch October 11, 2023 21:02
@vstinner vstinner mentioned this pull request Oct 13, 2023
Return value conventions capi-workgroup/api-evolution#13
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@vstinner vstinner vstinner approved these changes
@encukou encukou encukou left review comments
@AA-Turner AA-Turner AA-Turner left review comments
@ezio-melotti ezio-melotti ezio-melotti left review comments
@markshannon markshannon Awaiting requested review from markshannon

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

DO-NOT-MERGE Do not merge this PR

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Document the preferred style for API functions with three, four or five-way returns

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@erlend-aasland @vstinner @encukou @AA-Turner @ezio-melotti @willingc
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.