-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
PyIter_Next has ambiguous return value #105201
Comments
… an ambiguous return value
Before we rush to introduce new APIs, can we clarify the following:
I interpret this as:
Error means a raised exception. |
I don't think it's a good API for an iterator if you need to check 2 things just to know whether iteration completed, and then after the loop you need to check again why it was completed. |
Perhaps iterator APIs should get their own issue, since they require ambiguous return values? It seems to me they don't fit in the premises established by the OP. |
Sure, let make this issue about iterators. |
My proposal is to add a new The reason to do this and not So I am proposing:
rather than
|
CC @encukou |
I still fail to see how the problem "API A has ambiguous return value" is solved by introducing API B which also has an ambiguous return value. |
I’m giving up on incrementally fixing this in the current c api and will turn my attention to the new c api work. Those who warned me were right, unfortunately. |
(See discussion on the attached PR for the full picture). |
Isn't this overreacting? Ignoring Raymond's knee-jerk reaction, Erlend's feedback points to a real issue with how we've been talking about this, but is not a reason to give up on incremental fixes. The way I read Erlend's feedback is that the problem isn't that the result or return value is ambiguous, but that it requires calling |
I figured with two -1s and no other responses this would die due to "no consensus", and in general I think "is it worth it" discussions for incremental changes are always going to be opinionated/political, which is not really how I want to spend my time. But I'll reopen the issue and PR so we can continue. |
FWIW, here's my thoughts about this: I really liked an early variant of your PR where you had an Also, I appreciate that there is a dedicated place to record API problems and discuss them; I really appreciate Irit's hard work with managing all of this. API design is hard, and I think it is important to discuss proposed APIs thoroughly before landing a design2, rather than rushing that process and landing possibly premature solutions. I also understand that long discussions about new APIs can be discouraging. Footnotes
|
We should decide in general whether functions that effectively return a I strongly prefer the former: I think it makes for nicer flowing code, makes it harder to miss the error, and is (IMO) more idiomatic C. As to what the return values should be:
What is the "lesser" or "greater" result is somewhat subjective, but I think it makes for the least surprising API. There are three cases to deal with, the return code should reflect that. Any code using the function will need to handle all three cases, with two tests, but should be able to test for the most common case with a single test. The trio of values, The version returning an E.g. with while ((err = PyIter_NextItem(iterator, &next)) > 0) {
use(next);
Py_DECREF(next);
}
if (err <= 0) {
/* Cleanup */
return -1;
}
/* Done */ This sort of three value return is relatively common, so we should have a consistent, documented pattern for it. |
I agree with Mark on all points. I also think we should agree on and document the new API guidelines before solving any existing issues; that way, there will hopefully be fewer long and exhausting discussions for each new API. |
@markshannon That's not a bad option, I tried it in an earlier iteration and I'm not sure I landed on anything better. How would you fix @erlend-aasland I appreciate your remarks, but let's not refer to what happened on that PR as "discussion". Children of an impressionable age have access to GitHub and they might be reading this. We should teach them better than that. |
|
Assuming you want to keep the more general signature, then yes it does need more return values. enum {
ERROR = -1,
UNORDERED = 1,
LESS_THAN = 2,
GREATER_THAN = 4
EQUAL = 8
} See https://github.com/python/cpython/blob/main/Include/internal/pycore_code.h#L469 for why this seemingly odd choice makes sense. |
That sounds like a good direction. For
In a |
For For example, implementing a version of PyObject *
dict_get_probably_missing(PyDictObject *self, PyObject *key, PyObject *default)
{
PyObject *val;
int res = PyDict_GetItem(self, key, &val);
if (res == 0) {
return Py_NewRef(default);
}
if (res > 0) {
return val;
}
else {
return NULL;
}
} |
|
Can we please open a devguide issue for establishing and documenting these API guidelines, and then move the general discussion we're now having over there? When that discussion has landed, and guidelines are documented, we can |
I'm not going to pursue this. |
The C API WG voted on and agreed on the following API:
|
Return -1 and set an exception on error; return 0 if the iterator is exhausted, and return 1 if the next item was fetched successfully. Prefer this API to PyIter_Next(), which requires the caller to use PyErr_Occurred() to differentiate between iterator exhaution and errors. Co-authered-by: Irit Katriel <iritkatriel@yahoo.com>
Return -1 and set an exception on error; return 0 if the iterator is exhausted, and return 1 if the next item was fetched successfully. Prefer this API to PyIter_Next(), which requires the caller to use PyErr_Occurred() to differentiate between iterator exhaustion and errors. Co-authered-by: Irit Katriel <iritkatriel@yahoo.com>
Return -1 and set an exception on error; return 0 if the iterator is exhausted, and return 1 if the next item was fetched successfully. Prefer this API to PyIter_Next(), which requires the caller to use PyErr_Occurred() to differentiate between iterator exhaustion and errors. Co-authered-by: Irit Katriel <iritkatriel@yahoo.com>
As discussed in capi-workgroup/problems#1, we have some C API functions that have ambiguous return values, requiring the caller to query
PyErr_Occurred()
to find out whether there was an error.We will try to move away from those APIs to alternative ones whose return values non-ambiguously indicate whether there has been an error, without requiring the user to call
PyErr_Occurred()
.In this issue we will discuss the iterator API.
PyIter_Next
return NULL for both error and for the iterator being exhausted.PyErr_Occurred()
distinguishes between the cases.Linked PRs
The text was updated successfully, but these errors were encountered: