This was inspired by a tweet today from Brandon Rhodes. I looked for something like it on the mypy issues page and didn't find anything.

Would it make good semantic sense- and be useful- to specify valid numerical ranges using slices and type-hint syntax? My suggestion would be to, at minimum, provide this functionality for int and float.

Consider that currently we have:

x: int  # this means "all ints", today
x: float  # this means "all floating point numbers", today

Idea in a nutshell would be for the following type declarations to mean:

x: int[0:]  # any ints greater than or equal to zero would match, others would fail
x: int[:101]  # any ints less than 101 match
x: int[0:101:2]  # even less than 101

# for floats, it's a bit odd since the upper bound is typically exclusive...
# but we might prefer it to be inclusive? Not sure.
# regardless, any float within the range matches  
import math
x: float[-math.pi:math.pi] # any angle in radians from -pi to pi
x: float[-180:180]  # any angle in degrees from -180 to 180

So going with the angle example, one use-case might be something like:


import math

def atan_deg_int(v: float) -> int[-90:91]:
    """Computes the angle in integer degrees using arctangent."""
    return math.atan(v) * 180/math.pi

if __name__=="__main__":
    AngleDeg = float[0:360]  # a positive angle up to 360 degrees
    x: AngleDeg
    x = atan_deg_int(-0.5)

Then we would get an error similar to below:

>>> mypy
<string>:1: error: Incompatible types in assignment (expression has type "int[-90:91]", variable has type "float[0:45]")

Here the error occurs not because ints are considered inconsistent with floats (mypy allows ints in the place of floats, so no problem there), but because some of the ints from -90 to 90 (inclusive) fall out of the float range of 0 to 360.


"I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler