You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add public functions PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() #29
They should be identical to existing private functions _PyLong_IsPositive(), _PyLong_IsNegative() and _PyLong_IsZero(), except that the argument is PyObject * instead of PyLongObject *.
The private functions are much more used in the CPython code than _PyLong_Sign (numbers are not accurate):
New public API should take PyObject*, and raise TypeError on bad types. These don't do it. Is there any new reason to make an exception to that guideline? I'd hate to repeat the conversation in #19.
Most of the usage in CPython is in unicodeobject.c implemeting PyLong itself. I don't think that's representative for third-party usage.
The functions quite easy to implement using PyLong_GetSign. Is it really worth adding three extra API functions?
Even excluding Objects/longobject.c, there are much more use cases for these functions than for _PyLong_Sign (note that some of these cases for _PyLong_Sign can use _PyLong_IsNegative).
If you insist, we can make them returning 0 or setting an error and returning -1 if the argument is not a Python int. They will still be fast and convenient.
New public API should take PyObject*, and raise TypeError on bad types. These don't do it. Is there any new reason to make an exception to that guideline? I'd hate to repeat the conversation in #19.
PyLong already has exceptions: PyUnstable_Long_IsCompact() and PyUnstable_Long_CompactValue() parameter type is const PyLongObject* instead of PyObject*.
Maybe PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() belong to the PyUnstable API instead.
All uses outside of Objects/longobject.c currently require the argument to be cast to PyLongObject *. I am sure this will be the same in the user code.
When we use other pointer type than PyObject * in C, this makes the code less type safe.
Is it really worth adding three extra API functions?
As author of the PyLong_Sign() proposal, I would like to see these functions instead of the implemented PyLong_GetSign().
Original idea was to offer GMP-like interface - as mpz_sgn() - that take single PyLongObject* argument (or PyObject* and not raise errors on int's). That's just as convenient and readable as PyLong_Is* functions (at cost of one function, instead of several), e.g.:
if (PyLong_Sign(obj) <0) {
But with PyLong_GetSign() - this is impossible.
With API like
/* Returns 1 if the object obj is negative integer, and 0 otherwise. On failure, return -1 with an exception set. This function always succeeds if obj is a PyLongObject or its subtype. */intPyLong_IsNegative(PyObjectobj);
most consumers could use one-liners as in the issue description and not worry about calling PyErr_Occurred().
The functions quite easy to implement using PyLong_GetSign.
That's true. But I worry that all consumers of that API will end in implementing such wrappers (or PyLong_Sign-like one).
The gmpy2 project has just one place, that will call this API and this doesn't matter. But not all C API users so lucky.
Even excluding Objects/longobject.c, there are much more use cases for these functions than for _PyLong_Sign (note that some of these cases for _PyLong_Sign can use _PyLong_IsNegative).
To me it looks, that across the whole CPython codebase - only three calls to the _PyLong_Sign() do make sense: floatobject.c, _pickle.c and sliceobject.c. All could be converted to using _PyLong_Is* without loss in readability and, I think, with minimal impact on performance.
That's true. But I worry that all consumers of that API will end in implementing such wrappers (or PyLong_Sign-like one).
The gmpy2 project has just one place, that will call this API and this doesn't matter. But not all C API users so lucky.
For reference, which/how many other consumers are we talking about? I thought gmpy2 is the main user.
Based on that link, it looks like sage uses this in combination with other private API, to import/export int data without conversion. We should add API for that whole use case, not for one part of it.
I still think that projects that need these more than once or twice should implement them using PyLong_GetSign, handling the four possible results in the way that's most appropriate for them.
@encukou: You're against adding these 3 functions, but other voters are in favor of the addition. Can you consider changing your vote? Same remark question for the keep or remove PyLong_GetSign() vote.
BTW, the sentence "I still think that projects that need these more than once or twice should implement them using PyLong_GetSign, handling the four possible results in the way that's most appropriate for them." contradicts to vote for removing the PyLong_GetSign().
Activity
vstinner commentedon Jun 13, 2024
What are return values? Especially when the argument is not a Python int?
serhiy-storchaka commentedon Jun 13, 2024
1for true,0for false.They should be only used with a Python int, like
PyUnicode_IsIdentifier()can be only used with a Python str.skirpichev commentedon Jun 13, 2024
You meant for non-int's too, right?
Then using PyLongObject seems more logical. If so, I don't see why this is better than single
interface, already rejected in #19
PS:
Some compilers (e.g. recent gcc) also emit warning on the first line.
encukou commentedon Jun 14, 2024
New public API should take
PyObject*, and raise TypeError on bad types. These don't do it. Is there any new reason to make an exception to that guideline? I'd hate to repeat the conversation in #19.Most of the usage in CPython is in
unicodeobject.cimplemetingPyLongitself. I don't think that's representative for third-party usage.The functions quite easy to implement using
PyLong_GetSign. Is it really worth adding three extra API functions?serhiy-storchaka commentedon Jun 14, 2024
Even excluding
Objects/longobject.c, there are much more use cases for these functions than for_PyLong_Sign(note that some of these cases for_PyLong_Signcan use_PyLong_IsNegative).They are faster and more convenient. They are used in many different files:
If you insist, we can make them returning
0or setting an error and returning-1if the argument is not a Python int. They will still be fast and convenient.vstinner commentedon Jun 14, 2024
PyLong already has exceptions:
PyUnstable_Long_IsCompact()andPyUnstable_Long_CompactValue()parameter type isconst PyLongObject*instead ofPyObject*.Maybe PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() belong to the PyUnstable API instead.
serhiy-storchaka commentedon Jun 14, 2024
All uses outside of
Objects/longobject.ccurrently require the argument to be cast toPyLongObject *. I am sure this will be the same in the user code.When we use other pointer type than
PyObject *in C, this makes the code less type safe.skirpichev commentedon Jun 16, 2024
As author of the
PyLong_Sign()proposal, I would like to see these functions instead of the implementedPyLong_GetSign().Original idea was to offer GMP-like interface - as
mpz_sgn()- that take singlePyLongObject*argument (orPyObject*and not raise errors on int's). That's just as convenient and readable asPyLong_Is*functions (at cost of one function, instead of several), e.g.:But with
PyLong_GetSign()- this is impossible.With API like
most consumers could use one-liners as in the issue description and not worry about calling
PyErr_Occurred().That's true. But I worry that all consumers of that API will end in implementing such wrappers (or PyLong_Sign-like one).
The gmpy2 project has just one place, that will call this API and this doesn't matter. But not all C API users so lucky.
To me it looks, that across the whole CPython codebase - only three calls to the
_PyLong_Sign()do make sense: floatobject.c, _pickle.c and sliceobject.c. All could be converted to using_PyLong_Is*without loss in readability and, I think, with minimal impact on performance.encukou commentedon Jul 1, 2024
For reference, which/how many other consumers are we talking about? I thought gmpy2 is the main user.
serhiy-storchaka commentedon Jul 1, 2024
CPython itself uses such functions much more than the sign function.
vstinner commentedon Jul 1, 2024
If the main consumer is CPython, we can use the internal C API, no?
serhiy-storchaka commentedon Jul 1, 2024
CPython is just an example. Looking at the list of files where they are used you can see that they are usable in many different fields.
vstinner commentedon Jul 1, 2024
As I wrote previously, if you want
PyLongObject*argument, I suggest to add functions to the PyUnstable API.skirpichev commentedon Jul 2, 2024
Probably, sage is. gmpy2 is much less popular project.
https://github.com/sagemath/sage/blob/b7dd28d2456307802ce4ddcfc692331744f9b0db/src/sage/libs/gmp/pylong.pyx#L95
But for CPython sometimes
_PyLong_Sign()does make sense, e.g.:https://github.com/python/cpython/blob/92893fd8dc803ed7cdde55d29d25f84ccb5e3ef0/Modules/_pickle.c#L2127
For external projects, I think that Positive/Zero/Negative predicates will handle all use cases.
encukou commentedon Jul 2, 2024
Based on that link, it looks like sage uses this in combination with other private API, to import/export int data without conversion. We should add API for that whole use case, not for one part of it.
10 remaining items
encukou commentedon Oct 7, 2024
I still think that projects that need these more than once or twice should implement them using
PyLong_GetSign, handling the four possible results in the way that's most appropriate for them.vstinner commentedon Oct 14, 2024
@zooba: Would you mind to vote on these APIs?
zooba commentedon Oct 14, 2024
Done. I don't mind a soft/docs-only deprecation of
GetSign, but I see no reason to remove it.vstinner commentedon Oct 17, 2024
@encukou: You're against adding these 3 functions, but other voters are in favor of the addition. Can you consider changing your vote? Same remark question for the keep or remove PyLong_GetSign() vote.
skirpichev commentedon Oct 18, 2024
BTW, the sentence "I still think that projects that need these more than once or twice should implement them using PyLong_GetSign, handling the four possible results in the way that's most appropriate for them." contradicts to vote for removing the
PyLong_GetSign().encukou commentedon Oct 22, 2024
Looks like I'm outvoted. I'll change my vote on the 3 functions, so I don't block progress. But:
Did y'all consider that
PyLong_GetSignis new in 3.14? We'd be (soft-)deprecating it in the same release where it's added.zooba commentedon Oct 23, 2024
No I didn't. If it's not been released, then yeah, just remove it.
erlend-aasland commentedon Oct 30, 2024
A PR for adding
PyLong_IsPositive,PyLong_IsNegative, andPyLong_IsZerois up for review:skirpichev commentedon Nov 2, 2024
Then we have 3/3 votes for/against removing PyLong_GetSign(). What to do?
encukou commentedon Nov 4, 2024
I have re-set the vote, and marked Steve, Erlend & me as wanting to remove it.
Does anyone want to keep
PyLong_GetSign, even though it was only released in an alpha version?skirpichev commentedon Nov 13, 2024
Implementation was merged to main: python/cpython#126065
skirpichev commentedon Nov 19, 2024
What's decision for PyLong_GetSign? It seems more votes down...
vstinner commentedon Nov 20, 2024
I voted to remove
PyLong_GetSign(). I don't think that we need 4 functions to get a sign, 3 is already a lot :-)