-
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
Vote on PEP 757 – C API to import-export Python integers #45
Comments
I'd prefer being able to deprecate |
I address d.p.o comment also here:
Probably, this concern also could be resolved with a new Edit: lets look closer on the structure typedef struct PyLongExport {
int64_t value;
uint8_t negative;
Py_ssize_t ndigits;
const void *digits;
// Member used internally, must not be used for other purpose.
Py_uintptr_t _reserved;
} PyLongExport; Most public fields (negative/ndigits/digits) are required, else the whole API doesn't make sense. So, we left with one field: typedef struct PyLongExport2 {
uint8_t is_compact;
union {
struct {
uint8_t version;
int64_t value;
} compact_value;
struct {
uint8_t negative;
Py_ssize_t ndigits;
const void *digits;
// _reserved could be actually here.
} digit_array;
};
// Member used internally, must not be used for other purpose.
Py_uintptr_t _reserved;
} PyLongExport2; Or we could use just reserve enough room for struct {
int64_t value[2];
} compact_value; |
As long as we can support it, but it shouldn't be forced to live forever :)
Sure, but AFAIK there's no expectation of that being a zero-copy mechanism, and it is in a library that's expected to provide conversions between arbitrary formats. It seems that adding a But, not being able to fail with
Oh, right -- a version field would be better on No version anywhere means that if/when
Examples are 2's complement, or a 64-bit compact value with a separate sign bit. But the ability to deprecate functions is mainly useful for unknown unknowns. I can't see decades ahead. |
Not all. Only if this representation can't fit in 64-bit
Then I'm lost :( The It's used to describe "asymptotic" representation of CPython integers as "digit array". (Maybe PEP isn't clear enough here?) Which else field we might want to add to this structure?
I'm assuming you meant 2's complement for "compact" values, not for representation of big integers. Then both variants could be solved as described above:
If this complication is required - I'm slightly biased to (1). |
I dislike anonymous union, it caused us some troubles in the past.
I dislike having two numbers, you have to define the order. I don't think that it's needed. I suggest to revisit the API once Python will need 128-bit. For now, it only needs 60-bit. |
We can make a small change to PEP 757:
It doubles the capacity of |
What would be the point though? How likely is it that CPython switches to an uncommon "uint64 + sign bit" representation? @markshannon what do you think? |
It may simplify the code using this API: https://peps.python.org/pep-0757/#export-pylong-export-with-gmpy2 Currently, this code is needed: mpz_import(z, 1, -1, sizeof(int64_t), 0, 0, &value);
if (value < 0) {
mpz_t tmp;
mpz_init(tmp);
mpz_ui_pow_ui(tmp, 2, 64);
mpz_sub(z, z, tmp);
mpz_clear(tmp);
} I expect that it can be simplified to the following code which should be more efficient: mpz_import(z, 1, -1, sizeof(uint64_t), 0, 0, &value);
if (long_export.negative) {
mpz_neg(z, z);
} Note: currently, only Windows uses this code path, since Windows only has 32-bit C long for |
I should never have mentioned any examples. A |
I wrote python/peps#4025 to allow PyLong_Export() to fail. |
The goal of this API is not to simplify consumer code, it's to make the export as efficient as possible. To make the export as efficient as possible, it must be as close as possible to CPython's internal representation. CPython is much more likely to adopt a int64 representation internally, than a "uint64 + sign bit" representation. The latter simply doesn't make sense, because it can't fit in a machine register. Thus the export API should favor int64 over "uint64 + sign bit". |
Was it before or after adding the C11 compiler requirement? With union, the structure will be also smaller (both in the current variant & with version field).
Native. Something like that does make sense for me with hypothetical 128-bit machine int's. Using e.g. uint64_t + sign doesn't look as a possible future for CPython integers.
What about version field? |
In short, the Python C API only requires C99, not C11: see the long discussion. |
I don't think that we should add a |
The union doesn't need to be anonymous, let's just name it. How about:
(edit: the union should be last so the struct can grow) Maybe this discussion should be on Discourse, not here... |
Which problem are you trying to address with this different structure? |
Compared to @skirpichev's earlier proposal:
|
I'm not sure if anonymous unions are banned from public API. (The long discussion seems to be unfinished.) But the rest clearly does make sense. This even more closer to the original proposal by Antoine. |
@erlend-aasland @mdboom @serhiy-storchaka: What's your call on the PEP 757? |
Note that Import-API (which requires also PyLongLayout description for int's) from previous discussions seems much less controversial. I think it helps if C-API will have at least that part of PEP. Maybe it worth to make separate pools? The Export API + Layout API and the Import API + Layout API. |
We modified PEP 757 to remove the following sentence from
So you can now deprecate the function by emitting |
Nobody voted so far. Does it mean that you're against PEP 757, or just that you are waiting until the discussion settles down? |
I'm +0 for the current PEP. It does the job, but I think the |
@encukou, here you suggest that "other workarounds" for your concerns (including What do you think on the Import API (layout + PyLongWriter)? To me it looks PEP going to be rejected. If so, I don't see good reasons to loose that part (which got much less criticism) too. |
Yes, I changed my mind. But not much, I'm still +0 here. A disadvantage of the checkbox-based voting system is that it doesn't distinguish between “no”, “+0”, and “didn't vote yet”. The import API looks is fine to me. |
@mdboom @serhiy-storchaka @zooba: Would you mind to review PEP 757 (and vote)? |
One minor nit (which can be clarified in docs, as far as I'm concerned, rather than having to update the PEP) is the lifetime of the There's no mention in the PEP of limited API - is this going in? I think we should also add |
(I think it's fine, if updates are minor. Then we can copy-paste docs to the implementation pr.)
But there is no other options to free
I think it should be good enough for this. @vstinner? But note that now e.g. #29 is not going to be in the limited API. That's a better candidate.
And this; +1. |
You're right, I misread. It's an out parameter (which makes far more sense). So yes, no need to change anything. |
I would prefer to not add these APIs to the limited C API in Python 3.14. There is no need for that right now, it can be done later. |
You must call Finish or Discard to free digits. You cannot/must not free it explicitly. Technically, digits is a pointer to an integer digits: the memory is a PyLongObject object. But it's an implementation detail ;-) |
@mdboom @serhiy-storchaka: Gentle reminder: Would you mind to review PEP 757 (and vote)? Don't hesitate if you have doubts or questions. |
Based on @serhiy-storchaka feedback in python/cpython#111140 (comment), I would guess that he is seconded to the Mark's opinion in the discussion thread. I.e. it's better to have mpz_import/export-like API on the CPython side. We tried to address this concern here: https://peps.python.org/pep-0757/#provide-mpz-import-export-like-api-instead (this slightly updated by python/peps#4126). |
This issue is open for almost 2 months. PEP 757 got 4 positive votes, but @serhiy-storchaka didn't vote yet. Does the vote need 100% majority? |
I am very sorry for being a hindrance. I would prefer more mpz_import/mpz_export like API, but it has serious drawbacks: more complex code, not zero-copy, and most importantly, it only works with absolute values -- this makes it implementation dependent. The PEP addresses this option. Now, I don't want to delay the vote even further by bikeshedding. I am +1. |
Thanks Serhiy. I mark the PEP as Accepted and close the issue. The PR python/cpython#121339 is now ready for your final review :-) |
(You are not. 3.14.b1 scheduled on 2025-05-06. It's a long way to...)
That depends on the lib. Probably, most will offer GMP-like access to internals.
I would like to see some bigints library, with a different internals (say 2s complement).
(I would appreciate your bikeshedding on python/peps#4111.) |
The problem with the GMP-like interface would've been that the caller can specify the shape of the result. We didn't want to implement that, so it would likely have been a case where the caller has to provide exactly the settings that match our internal representation or they get an error. That's silly, so we use a different interface where we tell them how it's shaped. That's all that is different here. |
Does it work with LibTomMath (the library used in Tcl)? At least Python did not provide such access to inteomrnals before this PEP.
It seems that cpp_int in Boost implements this. I myself implemented a minimal arbitrary fixed size integer library on templates over 20 years ago, and 2s complement was a natural choice. |
I think so: the
(Isn't that just a wrapper to the GMP/TomMath?)
I would say this rather fits to extensions of machine integer arithmetic, i.e. of fixed precision (albeit arbitrary). Probably without need to something beyond school algorithms for arithmetic. |
Vote on PEP 757 – C API to import-export Python integers.
Since I co-authored PEP 757, I abstain from voting on my own PEP :-)
I closed the previous issue since it had a long history and the API changed multiple times.
The text was updated successfully, but these errors were encountered: