Title: BigInteger becomes long in Jython 2.7
Type: behaviour Severity: major
Components: Core Versions: Jython 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: alex.gronholm, jeff.allen, kaneg, zyasoft
Priority: high Keywords:

Created on 2015-07-24.03:32:37 by kaneg, last changed 2018-03-14.21:01:01 by jeff.allen.

msg10164 (view) Author: Kane Gong (kaneg) Date: 2015-07-24.03:32:36
BigInteger's behavior becomes different between Jython2.7 and 2.5. It made some Java related functions broken.

In Jython 2.5
Jython 2.5.3 (2.5:c56500f08d34+, Aug 13 2012, 14:48:36)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_51
>>> from java.math import BigInteger
>>> BigInteger.valueOf(1).abs()
>>> type(BigInteger.valueOf(1))
<type 'java.math.BigInteger'>
In Jython 2.7:
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.7.0_60
>>> from java.math import BigInteger
>>> BigInteger.valueOf(1).abs()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'long' object has no attribute 'abs'
>>> type(BigInteger.valueOf(1))
<type 'long'>
msg10169 (view) Author: Alex Grönholm (alex.gronholm) Date: 2015-07-29.20:08:26
Hm, BigInteger should map to long. Can you demonstrate a situation where this is a practical problem?
msg10170 (view) Author: Kane Gong (kaneg) Date: 2015-08-01.02:17:40
We have lots of code to calling methods of BigInteger, such as toByteArray(), abs() and etc. You can see my example, BigInteger.valueOf(1).abs() will fail in Jython 2.7. In Jython 2.5 it works well. I believe, Jython should be compatible with Java as its basic principle.
msg10171 (view) Author: Alex Grönholm (alex.gronholm) Date: 2015-08-01.08:18:19
It IS compatible with Java. In 2.7, BigInteger now behaves consistently with the rest of the numeric types, in that it properly transforms to and from Python types automatically. Would it be impossible for you to adapt to this? I assure you that this is not the only backwards incompatible change in the latest Jython.
msg10172 (view) Author: Kane Gong (kaneg) Date: 2015-08-02.07:03:38
As you said the BigInteger is indeed not the first Java Class that isn't compatible with Java, such as Float, Long and Short have the same issue.
Anyway, we will accept the reality if it is a feature to exchange data between Python and Java. 

Fortunately, I found a workaround to create a real BigInteger:
b1 = BigInteger.valueOf(9999) #Failed case, the result will be a long
b2 = BigInteger(str(9999))    #Success case, the result will be a BigInteger

I will downgrade the issue to minor. It can also be closed if someone thinks it is OK to accept the current behavior.
msg10173 (view) Author: Alex Grönholm (alex.gronholm) Date: 2015-08-02.08:55:36
It seems that invoking the constructor directly gives you a BigInteger, but not so if you get it by invoking one of the static methods. I have to talk to Jim Baker and confirm whether this is intended behavior. The other numeric types work this way too.
msg10174 (view) Author: Jeff Allen (jeff.allen) Date: 2015-08-07.21:48:40
I'll just inject that #2216 and #2090 are relevant here. We decided to convert BigInteger to long in response to those, and in particular the user surprise about expressions that mix Python numeric types with BigInteger. (I think there is still a problem with JSR-223, but that may be a different issue.)

I can see the OP's point. It is at least as surprising that BigInteger.valueOf(1).abs() should not evaluate as it was that BigInteger('10') would not compare correctly with an int.

Maybe the issue is with when we do the coercion, not whether?
msg11801 (view) Author: Jeff Allen (jeff.allen) Date: 2018-03-14.21:01:00
Hmm ... reading Kane's work-around makes me want to break it some more.

>>> b1 = BigInteger.valueOf(9999)
>>> b2 = BigInteger("9999")
>>> type(b1)
<type 'long'>
>>> type(b2)
<type 'java.math.BigInteger'>
>>> b1+1
>>> b2+1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'java.math.BigInteger' and 'int'
>>> b1==b2

This surely isn't what we intended in #2090. If we intend BigInteger to mix arithmetically with Python native types at all, we ought to accept it everywhere a long would be ok. And yet, when a Java type has useful instance methods, you'd prefer not to conceal them. BigInteger(n).abs() is not very compelling, but how about BigInteger(n).isProbablePrime(m), for example?

I think we may be coercing in the wrong place: surely a BigInteger had better keep its unique character until it meets an operator that just needs its long value?

Setting this to high because it raises architectural questions for which I feel we ought to have an answer. Maybe we do.
Date User Action Args
2018-03-14 21:01:01jeff.allensetpriority: high
messages: + msg11801
2015-08-07 21:48:41jeff.allensetnosy: + jeff.allen
messages: + msg10174
2015-08-02 08:55:36alex.gronholmsetnosy: + zyasoft
messages: + msg10173
severity: minor -> major
2015-08-02 07:03:39kanegsetmessages: + msg10172
severity: major -> minor
2015-08-01 08:18:19alex.gronholmsetmessages: + msg10171
2015-08-01 02:17:41kanegsetmessages: + msg10170
2015-07-29 20:08:27alex.gronholmsetnosy: + alex.gronholm
messages: + msg10169
2015-07-24 03:32:37kanegcreate