I sometimes find myself with this problem:
class Base: # Possibly an ABC
...
class SubA(Base):
...
class SubB(Base):
...
For example with custom exceptions, base ast nodes and so on.
Now I often want to use exhaustive pattern matching while excluding the base class, since it is often abstract.
In this case, I often find myself missing some way to describe “all subclasses of a type”. In this case, I would usually have to do:
... # Code from before
type AllSubclassesT = SubA | SubB
# And then I can exhaustively match:
def func_that_handles_all(sub: AllSubclassesT) -> Any:
match sub:
case SubA():
...
case SubB():
...
case _:
assert_never(sub)
If I add another subclass to my possibly long list of subclasses, I could easily forget it in the type alias and therefore my type checker won’t help me with handling all cases.
So for this case, a typing solution could be useful. It would scan the whole code for any class that subclass Base and then give you that statically as a union. Obviously, this wouldn’t work for dynamic class creation, but that is limited for static typing in many cases either way and not the main use case for this.
So basically:
...
from typing import SubclassesOf
type AllSubclassesT = SubclassesOf[Base] # SubA | SubB
Returning a tuple instead of a union is also an idea I had, but I’m pretty sure unions make all things possibly that tuples would make possible, but not vice versa.
The result of this new type could not be a tuple of any specific order, for example tuple[SubA, SubB] since the type checker CANNOT know the order of subclasses which this would most likely be based off and therefore it would be ambiguous. Therefore tuple[SubA | SubB, ...] is the best type hint we can produce. But we can just do tuple[SubclassesOf[Base], ...] of the union result version and have this case included. Going from a tuple to union is (I think) not possible currently.
What do you think? Do you think this is feasible (especially to scan all files for classes or another idea)?
I just wanted to share the idea since I had this problem before.