>you better believe that every single admissible type will eventually be fed to this function
That's your problem right there. Why are random callers sending whatever different input types to that function?
That said, there are a few existing ways to define that property as a type, why not a protocol type "Indexable"?
>why not a protocol type
it was a sin that python's type system was initially released as a nominal type system. they should have been the target from day one.
being unable to just say "this takes anything that you can call .hello() and .world() on" was ridiculous, as that was part of the ethos of the dynamically typed python ecosystem. typechecking was generally frowned upon, with the idea that you should accept anything that fit the shape the receiving code required. it allowed you to trivially create resource wrappers and change behaviors by providing alternate objects to existing mechanisms. if you wanted to provide a fake file that read from memory instead of an actual file, it was simple and correct.
the lack of protocols made hell of these patterns for years.
I disagree. I think, if the decision was made today, it probably would have ended up being structural, but the fact that it isn't enables (but doesn't necessarily force) Python to be more correct than if it weren't (whereas forced structural typing has a certain ceiling of correctness).
Really it enabled the Python type system to work as well as it does, as opposed to TypeScript, where soundness is completely thrown out except for some things such as enums
Nominal typing enables you to write `def ft_to_m(x: Feet) -> Meters: and be relatively confident that you're going to get Feet as input and Meters as output (and if not, the caller who ignored your type annotations is okay with the broken pieces).
The use for protocols in Python in general I've found in practice to be limited (the biggest usefulness of them come from the iterable types), when dealing with code that's in a transitional period, or for better type annotations on callables (for example kwargs, etc).
TypeScript sacrificed soundness to make it easier to gradually type old JS code and to allow specific common patterns. There is no ceiling for correctness of structural typing bar naming conflicts.
>The use for protocols in Python in general I've found in practice to be limited (the biggest usefulness of them come from the iterable types)
Most Python's dunder methods make it so you can make "behave alike" objects for all kinds of behaviors, not just iterables
AFAIK, Python is missing a fully-featured up to date centralized documentation on how to use type annotations.
The current docs are "Microsoft-like", they have everything, spread through different pages, in different hierarchies, some of them wrong, and with nothing telling you what else exists.
> That's your problem right there. Why are random callers sending whatever different input types to that function?
Because it’s nice to reuse code. I’m not sure why anyone would think this is a design issue, especially in a language like Python where structural subtyping (duck typing) is the norm. If I wanted inheritance soup, I’d write Java.
Ironically, that’s support for structural subtyping is why Protocols exist. It’s too bad they aren’t better and the primary way to type Python code. It’s also too bad that TypedDict actively fought duck typing for years.
Why can’t you re-use it with limited types? If the types are too numerous/hard to maintain it seems like the same would apply to the runtime code.
Because it’s nice to reuse code. It’s virtually never the case that a function being compatible with too many types is an issue. The issue is sometimes that it isn’t clear what types will be compatible with a function, and people make mistakes.
Python’s type system is overall pretty weak, but with any static language at least one of the issues is that the type system can’t express all useful and safe constructs. This leads to poor code reuse and lots of boilerplate.
>It’s virtually never the case that a function being compatible with too many types is an issue
This kind of accidental compatibility is a source of many hard bugs. Things appear to work perfectly, then at some point it does something subtly different, until it blows up a month later
if the piece of code in question is so type independent, then either it should be generic or it's doing too much
Yes. It's not the type system that's broken, it's the design. Fix the design, and the type system works for you, not against you.
> Why are random callers sending whatever different input types to that function?
Probably because the actual type it takes is well-understood (and maybe even documented in informal terms) by the people making and using it, but they just don’t understand how to express it in the Python type system.