Numeric Tower / Union[float, int]
See original GitHub issueI think I found an edge case with the annotation float
when passed an int
in beartype
. For convenience, PEP484 accepts int when float
is annotated: https://www.python.org/dev/peps/pep-0484/#the-numeric-tower
from beartype import beartype
@beartype
def measure_cave(length: float, width: float):
return length * width
measure_cave(12.0, 12.0) # PASS
measure_cave(12, 12) # type hint <class 'float'>, as "12" not instance of float.
I’m currently using Union[float, int]
to work with beartype and wondered if you would consider implementing the PEP484 “numeric tower” logic or keep beartype as-is?
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:12 (2 by maintainers)
Top Results From Across the Web
mypy, type hint: Union[float, int] -> is there a Number type?
Use float only, as int is implied in that type: def my_func(number: float):. PEP 484 Type Hints specifically states that:.
Read more >Raymond Hettinger on Twitter: "#Python typing question: Is there ...
Due to the numeric tower, saying "float" is equivalent to "Union[int, float]". Answering Raymond: no, there is never a reason to be explicit...
Read more >Typing the Numeric Tower - Northwestern Computer Science
3.1 Union types. Typed Racket provides general union types. For example, (U Integer Float) con- tains all integers as well as all floating-point...
Read more >Issue 47234: PEP-484 "numeric tower" approach makes it ...
Real` instead (which may well need better support by tooling), respectively express "can be int or float" as `Union[int, float]`.
Read more >mypy, type hint: Union[float, int] - is there a Number type?
PYTHON : mypy, type hint: Union [ float, int ] - is there a Number type? [ Gift : Animated Search Engine ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
⚠️ THREADJACK RISK ⚠️ - Consider ignoring this comment and proceeding as if it didn’t exist.
Ah, yes. The good ol’ numeric tower. A source of perfection and clarity and zero controversy and not at all a half-finished-but-advertised-as-complete home for all things number-related. Consider:
—gvanrossum, 2017
—gvanrossum, 2017
—gvanrossum, 2020
So at least that guy is slowly coming around. 👌😅
I will encourage @leycec to weigh in here regarding the specific issue of treating
int
as a subclass offloat
within beartype, not only because this is his show, but because his mastery far exceeds my own. However, if you want native number compatibility as well as compatibility with the numeric tower generally, that’s probably an effort that you will struggle with beyond beartype.This work-around may help you if you need something right now:
What’s kinda cool about that approach is that this also works:
Why the
operator.__mul__
, you ask? Great question! Thanks for asking.SupportsFloat
is a Protocol that only requires that a thing define the__float__
method, not any operators. One alternative is:But I generally don’t like that, because conversions to native
float
s can be lossy. Be warned, however, that Protocols are devastatingly non-performant for runtime checks (if that’s what you find yourself doing). So much so that some of us have felt compelled to implement our own caching layer as a work-around. 🙄 If true support for arbitrary participants in the numeric tower is what you’re after, let me know if you’d like to discuss further, and I’ll carve out another place for that without further polluting your issue.This is such a great issue. I’m so grateful to our crack commando squad of black-ops typing aficionados for repeatedly weighing in. They say what I cannot, for they are smart and I am tired. This is what happens when your eyes get encrusted with the detritus of sleep deprivation: you wait for @posita and @TeamSpen210 to pierce the darkness for you.
tl;dr
Yuppers. We’re prolly sticking with either:
I am so, so sorry for what I have done to your codebase.
Why Are You So Horrible, @leycec?
Yes, @leycec is a Bad Enough Dude (BED).
With extreme apologies to AI King @KyleKing, please don’t send the robot dogs PEP 484, mypy, and (yuppers) Guido himself,
@beartype
would prefer to selectively pretend that something that was standardized wasn’t standardized. That is to say, we’re pretty sure Guido and those who approved PEP 484 got it wrong there.As @posita himself unearthed from Guido’s inbox, DropBox power! Guido himself now acknowledges the ubiquitous world-straddling girth of PEP 3141. PEP 3141 came first and PEP 484 failed to deprecate PEP 3141; ergo, PEP 3141 takes precedence. Suck it, PEP 484.
Non-Euclidean Numeric Tower, We Invoke Thee!
So. Here we stand on the crumbling shores of a long-forgotten derelict civilization. The principal issues with PEP 3141 and the standard
numbers
module are (in increasing order of impotence):beartype
O(n)
costs, which is admittedly horrifying. Back before I became disillusioned by theveil of Mayagritty facade of reality, I was once pretty sure thatABCMeta
efficiently cached (and thus effectively amortized) those costs. Having just reexamined thetyping.py
implementation in Python 3.10, I no longer know anything. Those costs might very well not be cached, in which case we can only collectively sigh and fling ourselves into the sea.So.
numbers
had an advertising problem. But that wasn’t the fault ofnumbers
; that was the fault of the humans surroundingnumbers
. Humanity, you have much to answer for.So.
numbers
probably also has an efficiency problem. That absolutely is the fault ofnumbers
and (more generally) the standardabc
module underlyingnumbers
. Remind me to never useABCMeta
inbeartype
. ←oh gods we already did it 5 timesWhat Could Possibly Go Wrong? Everything. Everything Could.
The principal issue with transparently treating
float
asint
is that it’s wrong – especially in the numeric contexts that@beartype
increasingly finds itself deployed to (e.g., finance, machine learning).Floats aren’t integers. Integers aren’t floats. There exist a countably infinite number of integers with no precise floating-point representation; likewise, there exist an uncountably infinite number of floats with no corresponding integer representation.
Floats and integers are not losslessly coercible into one another is what I’m sayin’. Converting one into the other results in a loss of precision in both the average and worst case. This is why numeric frameworks like NumPy recently moved from implicit to explicit
float
<->int
coercions. Previously, NumPy implicitly coerced dtypes to and fromfloat
andint
; now, NumPy requires you to explicitly permit NumPy to do that if you want NumPy to do that.This is a good thing. Explicit is better than implicit, because we are all enlightened light beings here. You may now be thinking: “Go to Heck, @leycec! You go to Heck and sleep fitfully there.” Wait. I thought you were an enlightened light being!?!? I can only reply: “You may punch me in my fat gullet in five minutes if you remain fully unconvinced.” would i lie
If
beartype
implicitly accepts integers for allfloat
type hints, thenbeartype
prosumers will no longer be able to prevent their userbase from erroneously passing integers. Right? In 2021, most industrial-strength APIs really want to prevent their userbase from erroneously passing integers where floats are required. Currently,beartype
supports this sensible constraint out-of-the-box at runtime – which is far more valuable than a static type checker supporting this sensible constraint out-of-the-box at static type-checking time.If
beartype
implicitly accepts integers for allfloat
type hints, thenbeartype
prosumers will have to resort to beartype validators to forcebeartype
to revert back to its prior sensible behaviour: e.g.,Don’t Believe Me. Believe Those Who Believe Me.
alibi
, a popular ML-splaining framework (it’s like mansplaining, only done by AI), wants to usebeartype
. This use is contigent onbeartype
behaving sanely. Currently,beartype
behaves sanely by raising human-readable exceptions when@beartype
-decorated callables annotated as accepting floats are passed integers. There are, like, a hundred of these test-time unit test failures, and stuff:Curiosity maimed the honey-addicted bear, so I noticed that and suggested they might globally replace
float
withnumbers.Real
in their type hints. Turns out they meant what they said and said what they meant. They actually did meantfloat
, because all of their callables only accept floats; they do not accept integers. Now, they can trivially enforce this with righteous@beartype
power:Are you gonna break
alibi
? I ain’t gonna breakalibi
. I like my kneecaps where they are – loosely attached to my legs.Cost-Benefit Analysis
Now we’re into the hard stuff. Dust off those Grandma-era liquor cabinets, because we are going there.
These Are the Costs of an Irresponsible Life
Costs of
@beartype
not implicitly accepting integers forfloat
type hints:@beartype
collapses under a rising tide of unpaid legal fees and collective Internet outrage.And… that’s about it. “But, wait! You calloused fool! What about mypy? Won’t someone think about the static type-checker?”, you are now venting. I can hear you over there, by the way.
Fine, fine. We don’t do what static type checkers do. But that’s permissible here, because static type checkers are (arguably) too permissive here. Mypy won’t emit errors or warnings for callables type-hinted with
Union[float, int]
instead offloat
, because the former is semantically equivalent to the latter from the static type-checking perspective.So. The only cost remains RSI. You’ve got it. I’ve got it. We’ve all got it. What’s 12 characters more when your wrist has already been ground down into a thin bone spur of unadulterated pain?
These Are the Benefits of an Irresponsible Life
Benefits of
@beartype
not implicitly accepting integers forfloat
type hints:int
where afloat
was expected is a bug in the general case, because: …cue trippy acoustic guitar campfire sing-a-longThese Are the Conclusions of the Starship Bearaprise
On the one hand, we’re giving everyone a permanent, crippling, debilitating physical injury that they already have. On the other hand, we’re doing our jobs.
And… We’re Goin’ Back to PEP 484
Anyone else notice the PEP 484 subsection we’re debating is super-weird? First, there’s this choice nugget:
There aren’t, actually. Okay, okay.
O(n)
runtime complexity is a problem – but not for most techbros. We’re the only ones who care about that. Anyone else notice how none of the supposed issues were actually enumerated or even mentioned? Guido throwin’ some baseless shade right there. Then there’s this even choicer nugget:OMG. There is not an ASCII emoji in my favourite PEP standard. There just isn’t. But… there is. Anyone else notice how this entire subsection reads more like casual email-speak than the quasi-formal standards-speak of the rest of the PEP? It’s almost like… no one actually even peer-reviewed or edited this subsection. Just sayin’.
We continue on our feeble death march with this frank admission:
Yes? And? Why aren’t we doing that? Because that’s what we should be doing.
Oh, bollocks. PEP subsection straight-up admitted it adopted a suboptimal, less effective solution than the previously standardized solution – just 'cause. No demonstrable justifications are given. Guido himself now acknowledges that
numbers
is preferable.So, bollocks. We defy the established order, because we are
beartype
. We are preserving a distinction betweenfloat
andint
, because there is a distinction betweenfloat
andint
. The two are not transparently interchangeable and any attempt to treat them as such invites type safety violations and the immanent destruction of the supposedly incomplete Death Star.A Pox on Beartype’s House
That said… let’s leave this open for all eternity.
There are extremely valid insights on bold sides of the opinion-littered back alley here. I invite them! Come! Berate me, excoriate my avatar, burn a miniature effigy of Mr. Nectar Palm (the @beartype mascot, yo) on your front lawn and then tweet us an animated GIF of the ensuing wreckage!
Do this in rembrance of this issue. Someday, even @leycec too may change his unsubstantiated worldview on QA.