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
it's not possible to define an 'add' that works with more than one kind of number when using number types directly #12899
I can't figure out how to write generic numeric code.
This is already covered to some extent by #3186, but that's about a higher-level numeric tower issue, rather than the very practical issue of code that can just work with int or float but has to keep the number type straight.
I actually want | Decimal | Fraction in there, but that makes the problem worse.
The same issue seems to occur with Generics.
Expected Behavior
No errors.
Actual Behavior
add.py:7: error: Incompatible return value type (got "float", expected "Num")
add.py:7: error: Unsupported operand types for + (likely involving Union)
Found 2 errors in 1 file (checked 1 source file)
I understand how this would not work if I were using division, or if there were some other variance on Num but is there really some way to add an int to an int and get a float?
Your Environment
Mypy version used: mypy 0.960 (compiled: yes)
Mypy command-line flags: None
Mypy configuration options from mypy.ini (and other config files): None
Python version used: Python 3.10.4 from python.org
changed the title [-]it's not possible to define an 'add' that works with more than one kind of number[/-][+]it's not possible to define an 'add' that works with more than one kind of number when using number types directly[/+]on May 28, 2022
This seems to work? It still has the problem of "mixing int and float is allowed, and results in float results" but this is like #9015 in that it's an intentional if unfortunate compromise with reality
Another workaround (that still allows mixing int and float) seems to be using a constrained type variable:
fromtypingimportTypeVarNum=TypeVar("Num", int, float)
defadd(a: Num, b: Num) ->Num:
returna+breveal_type(add(1, 2)) # N: Revealed type is "builtins.int"reveal_type(add(1, 2.0)) # N: Revealed type is "builtins.float"reveal_type(add(1.0, 2)) # N: Revealed type is "builtins.float"reveal_type(add(1.0, 2.0)) # N: Revealed type is "builtins.float"
I think mypy is somewhat correct in erroring on your original example because subclassing float is allowed. In this example:
fromtypingimportTypeVar# mypy is probably treating int | float the same as float hereNum=TypeVar("Num", bound=float)
classC(float):
passdefadd(a: Num, b: Num) ->Num:
returna+b# E: Incompatible return value type (got "float", expected "Num")reveal_type(add(C(), C())) # N: Revealed type is "__main__.C"
mypy infers Num to be C in the first call, even though add will return a float because C doesn't override __add__. Using a constrained type variable avoids this by solving Num as float in that case.
The workaround with an Addable protocol seems like a mypy bug, since it doesn't seem to error when using a subclass of float like above.
Activity
[-]it's not possible to define an 'add' that works with more than one kind of number[/-][+]it's not possible to define an 'add' that works with more than one kind of number when using number types directly[/+]glyph commentedon May 28, 2022
I guess the workaround looks like this?
This seems to work? It still has the problem of "mixing
intandfloatis allowed, and results in float results" but this is like #9015 in that it's an intentional if unfortunate compromise with realitypranavrajpal commentedon May 29, 2022
Another workaround (that still allows mixing
intandfloat) seems to be using a constrained type variable:I think mypy is somewhat correct in erroring on your original example because subclassing
floatis allowed. In this example:mypy infers
Numto beCin the first call, even though add will return a float becauseCdoesn't override__add__. Using a constrained type variable avoids this by solvingNumas float in that case.The workaround with an
Addableprotocol seems like a mypy bug, since it doesn't seem to error when using a subclass offloatlike above.erictraut commentedon Aug 13, 2023
I think mypy is doing the right thing here. I don't consider this a bug.
JelleZijlstra commentedon Aug 13, 2023
The OP's example with latest mypy (https://mypy-play.net/?mypy=latest&python=3.10&gist=433772fa66fc4f012b485d036496cc89) still produces these errors:
I think the first error is correct but the second is a bug. Pyright only produces a single error, equivalent to the
return-valueerror.If you change the return type to
float, theoperatorerror is still emitted, but Pyright accepts the code, I think correctly.