A *very* common pattern I see with type aliases is to have a large union of types imported from various modules, including third-party libraries
This proposal does not remove or deprecate `Union`. Anonymous sum types (`Union`) and nominal sum types (`sealed`) would live side-by-side just as anonymous product types (`tuple`) and nominal product types (`dataclass`) do today. If there is no relationship between the subtypes (like UsernameOrPassword), then by all means, use a Union, but a type hierarchy is still very appropriate when the subtypes are related (like Result).
This goes against the spirit of static duck typing, where we shouldn't have to reach into a class definition and add a parent just to make it acceptable to the type system. With `sealed`, we are limited to classes defined by the user in the same module. In real-world code, I find a lot of examples of unions of types imported from different modules, but very few of the same-module classes that you have. How often do you think this will be used?
Yep, this unashamedly goes against the spirit of duck typing. This is a nominal typing feature. I searched my current project and counted 27 instances of abstract base classes whose subclasses were all defined in the same file. Now, I am not sure how many of them would break if I added a subclass, (I am pretty sure that some of them would be fine because consumers should only use abstract methods), but that's kind of the point. A `sealed` decorator would make that contract explicit. Consumers of the class would know when exhaustive matching was allowed. I would know when I was breaking that contract and mypy would show me all the matches that needed to be fixed when I did.
Doesn't your proposal also require the base class to be written an extra time for each subclass? For example, in your motivating example, Node, Expression, and Statement are repeated for each subclass.
True. That feels like the minimum price to pay for inheritance, but I can see how other people could feel differently.