Skip to content
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

float**float return type #1406

Closed
gvanrossum opened this issue Jun 13, 2017 · 13 comments · Fixed by #2662
Closed

float**float return type #1406

gvanrossum opened this issue Jun 13, 2017 · 13 comments · Fixed by #2662
Labels
stubs: false positive Type checkers report false errors

Comments

@gvanrossum
Copy link
Member

float**float is currently defined as returning float, but in Python 3, (negative float) ** (non-whole float) returns a complex number. (In Python 2 it raises ValueError.)

I'm not sure what to do about this -- in mypy a plugin won't be very effective, because typically the sign of the base (left operand) is not known statically (as opposed to the exponent, which is often a literal, which is how we addressed this for int**(negative int)).

Declaring the result a complex is technically correct (since float is effectively a subclass of complex, just like int is effectively a subclass of float), but probably going to be a pain. Making it Union[float, complex] is likely worse. Keeping it float is a lie and may lead to unanticipated errors, and making it Any (like we do for int**int when we don't know the sign of the exponent) a cop-out that just hides more errors.

All in all I think we should change this to complex, even if it's a pain. Any other opinions?

@JukkaL
Copy link
Contributor

JukkaL commented Jun 14, 2017

Making it Any or complex seem like the most reasonable options. For consistency with how int**int and open are annotated (they have Anys in their return types) we could make the return type Any.

srittau added a commit to srittau/typeshed that referenced this issue Sep 11, 2018
__pow__ will return a float or complex value, depending on the input
values. While float is a subtype of complex, it will be inconvenient
for callers to handle a complex return value.

Closes python#1406
@srittau
Copy link
Collaborator

srittau commented Sep 11, 2018

I would also slightly prefer returning complex instead of Any. This is mostly going to be used in mathematical applications that can be expected to handle this case. If it turns out to be a huge pain in practice, we can always change to Any later.

@srittau srittau added the stubs: false positive Type checkers report false errors label Oct 28, 2018
utkarsh2102 added a commit to utkarsh2102/typeshed that referenced this issue Dec 1, 2018
utkarsh2102 added a commit to utkarsh2102/typeshed that referenced this issue Dec 1, 2018
utkarsh2102 added a commit to utkarsh2102/typeshed that referenced this issue Dec 1, 2018
@srittau
Copy link
Collaborator

srittau commented Dec 2, 2018

PR #2662, which implements this, causes CI to fail, due to problems with the sample code copied from the standard lib's random module. A fix for this is in python/mypy#5988. This is a good example of real world code that this would affect. I am still in favor of using a complex return type instead of Any, but I do not work with mathematical code a lot.

@utkarsh2102
Copy link
Contributor

I still did not understand the reason for CI failure :/

@srittau
Copy link
Collaborator

srittau commented Dec 2, 2018

Returning complex instead of float from __pow__() makes some implementations fail that assumed it to return float. We need to discuss whether that is acceptable or we need a different solution.

@utkarsh2102
Copy link
Contributor

Ah, okay.

@gvanrossum
Copy link
Member Author

I would be unhappy if we changed this to -> complex. I think it's a design mistake that we made this work in Python 3 in the first place -- if you look at the math and cmath modules, the guiding principle there is that the functions in math never return complex results, only the ones in cmath do. The equivalent rule for ** would have been to preserve the Python 2 behavior, where (-1)**0.5 raises ValueError, and if you want a complex result you have to use e.g. complex(-1)**0.5. (Concrete example: math.sqrt(-1) raises ValueError, while cmath.sqrt(-1) returns 1j.)

For the similar case of int/int, when we made this return float int Python 3, we did it differently: it always returns float, even if the result is mathematically an integer.

I expect it would be hugely inconvenient if e.g. x**0.5 were to be inferred as a complex value -- it would encourage people to add useless asserts or # type: ignore comments or even casts just to make mypy understand that the expected result is a float (because x is known or assumed to be nonnegative).

@utkarsh2102
Copy link
Contributor

This makes sense.
@srittau, should I change complex to Any then?

@gvanrossum
Copy link
Member Author

Why not leave well enough alone? If someone uses a**b with negative a and expects a complex, let them rewrite it as complex(a)**b.

@utkarsh2102
Copy link
Contributor

utkarsh2102 commented Dec 3, 2018

As far as I understand, in #2662, I think there should only be an overload for when x is an int, rest should be as it was before. I hope I'm not missing anything here?

@srittau
Copy link
Collaborator

srittau commented Dec 3, 2018

I am a bit conflicted on this issue. On the one hand, returning float - while probably correct in the majority of cases - can hide bugs (but so can returning Any). On the other hand, as Guido said, returning complex is a big pain, as python/mypy#5988 shows. As someone who doesn't write much mathematical code, I'll defer to Guido's judgement.

So basically, revert the changes the changes, no overload, just return float as before. But it would be helpful to add a comment to __pow__() that it returns complex if self is negative and x is not whole.

@srittau
Copy link
Collaborator

srittau commented Dec 3, 2018

Also, in my ongoing effort to promote AnyOf (python/typing#566), this would be a good use case. Same for range types (python/typing#554).

@utkarsh2102
Copy link
Contributor

Sure, on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stubs: false positive Type checkers report false errors
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants