|
| 1 | +# infinity and not-a-number float literals |
| 2 | + |
| 3 | +python has no literal syntax for the special floating-point values, so they have |
| 4 | +no literal *type* either — an annotation cannot say "this is infinity". basedpython |
| 5 | +adds three special float-literal types, written as attributes of `float`: |
| 6 | + |
| 7 | +- `float.inf` — positive infinity |
| 8 | +- `-float.inf` — negative infinity |
| 9 | +- `float.nan` — not-a-number |
| 10 | + |
| 11 | +they exist only in **type positions**. the transpiler erases each to plain `float` |
| 12 | +in the emitted python, since the runtime has no spelling for them: |
| 13 | + |
| 14 | +```by |
| 15 | +def clamp(lo: -float.inf, hi: float.inf) -> None: |
| 16 | + ... |
| 17 | +``` |
| 18 | + |
| 19 | +transpiles to: |
| 20 | + |
| 21 | +```python |
| 22 | +def clamp(lo: float, hi: float) -> None: |
| 23 | + ... |
| 24 | +``` |
| 25 | + |
| 26 | +## the literal types |
| 27 | + |
| 28 | +bound as parameters so the inferred type can be revealed: |
| 29 | + |
| 30 | +```by |
| 31 | +def f(pos: float.inf, neg: -float.inf, nan: float.nan) -> None: |
| 32 | + reveal_type(pos) # revealed: inf |
| 33 | + reveal_type(neg) # revealed: -inf |
| 34 | + reveal_type(nan) # revealed: nan |
| 35 | +``` |
| 36 | + |
| 37 | +## each is a subtype of `float` |
| 38 | + |
| 39 | +a special float literal is assignable to `float`, but a plain `float` is not |
| 40 | +assignable back to the literal — same direction as any literal-to-base relation: |
| 41 | + |
| 42 | +```by |
| 43 | +def f(inf: float.inf, x: float) -> None: |
| 44 | + a: float = inf |
| 45 | + b: float.inf = x # error: [invalid-assignment] |
| 46 | +``` |
| 47 | + |
| 48 | +## infinities keep their sign |
| 49 | + |
| 50 | +`float.inf` and `-float.inf` are distinct types — a positive infinity is not a |
| 51 | +negative one: |
| 52 | + |
| 53 | +```by |
| 54 | +def f(pos: float.inf) -> None: |
| 55 | + neg: -float.inf = pos # error: [invalid-assignment] |
| 56 | +``` |
| 57 | + |
| 58 | +## nan is signless |
| 59 | + |
| 60 | +a nan carries no sign, so `-float.nan` is the same type as `float.nan`: |
| 61 | + |
| 62 | +```by |
| 63 | +def f(nan: float.nan) -> None: |
| 64 | + also_nan: -float.nan = nan |
| 65 | + reveal_type(also_nan) # revealed: nan |
| 66 | +``` |
| 67 | + |
| 68 | +## type-position only |
| 69 | + |
| 70 | +these are *types*, not values. python's runtime `float` has no `inf` / `nan` |
| 71 | +attribute, so writing `float.inf` in a value position is rejected by the checker |
| 72 | +and would fail at runtime — use the standard library (`math.inf`, `math.nan`, or |
| 73 | +`float("inf")`) for the actual values: |
| 74 | + |
| 75 | +```by |
| 76 | +x: float = float.inf # error: [unresolved-attribute] |
| 77 | +``` |
0 commit comments