Skip to content

Local type inference of numeric variables #8747

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

Open
aecay opened this issue Apr 29, 2020 · 6 comments
Open

Local type inference of numeric variables #8747

aecay opened this issue Apr 29, 2020 · 6 comments

Comments

@aecay
Copy link
Contributor

aecay commented Apr 29, 2020

I have a very simple example program that produces surprising and (I think...) wrong behavior:

foo = 0

foo = 1.0

Running mypy against this file yields

test.py:3: error: Incompatible types in assignment (expression has type "float", variable has type "int")

But foo could(/should) be inferred as a float in this environment. I draw this conclusion from PEP-484

when an argument is annotated as having type float, an argument of type int is acceptable

(although this is not about function arguments per se).

I know that some improvements have been recently been made to type inference in 0.770 to use information from second (or subsequent) assignments, rather than just the first assignment. So maybe a widening from int to float could be implemented in the same way...?

@emmatyping
Copy link
Member

When you say foo = 0, foo is inferred having type int, so assigning a float is invalid. The reverse is allowed, as the PEP specifies. Mypy infers the type of a variable (usually) based on its first assignment.

The workaround is to do something like:

foo: float = 0
foo = 1.0

@aecay
Copy link
Contributor Author

aecay commented Apr 30, 2020

I understand the workaround -- I guess my question is, can the inference algorithm be extended to infer type float for foo in the example above, in a similar way to how 0.770 extended it to infer List[int] for foo in:

foo = []
foo += [1,2]

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Apr 30, 2020

You can use --allow-redefinition.

~/delete λ cat test66.py                                                                                            1 
foo = 0
print(foo)
foo = 1.0
reveal_type(foo)
~/delete λ mypy test66.py                     
test66.py:3: error: Incompatible types in assignment (expression has type "float", variable has type "int")
test66.py:4: note: Revealed type is 'builtins.int'
Found 1 error in 1 file (checked 1 source file)
~/delete λ mypy test66.py --allow-redefinition                                                                      1 
test66.py:4: note: Revealed type is 'builtins.float'

Note the print is necessary, as mentioned in #6963 / #6959 (comment)

@JukkaL
Copy link
Collaborator

JukkaL commented May 1, 2020

More generally, it may make sense to generalize type inference to allow cases like this (this isn't supported by --allow-redefinition):

x = 0
x += 1.2

The implementation could use the same approach used for the list example shown above (partial types).

Before moving forward with this, however, we'd need some evidence of how often this would be helpful. It's possible that generalizing partial types to floats wouldn't help much.

It might better to improve the error messages to propose adding a : float type annotation, for example.

@aecay
Copy link
Contributor Author

aecay commented May 1, 2020

how often [partial type inference] would be helpful. It might better to improve the error messages to propose adding a : float type annotation

From my own POV, I think smarter inference would always be preferable to having to add an annotation. However, I can imagine at least in principle a kind of code where this would not be helpful: if someone was relying on the type checker to help them keeps ints and floats separate (I guess this would be some kind of numeric/scientific code...?) I have no experience writing code of that type but I know python is a big tent so I agree we need to see if there are such uses in the wild!

(And if there are enough of those kind of uses to make a change to the inference undesirable, then a better still error message would be a good improvement.)

@JukkaL
Copy link
Collaborator

JukkaL commented May 1, 2020

Another thing that might make better inference undesirable if the better inference only works in, say, 30% of typical use cases. It may be better to have something where you consistently have to add an annotation compared to something where you usually need to add an annotation but sometimes not. Predictability is nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants