Sorry if I gave the wrong impression, I work in Python so my examples would be Python.
In any case, the PEP gives this Rust example:
```
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
```
and then it proceeds to translate it into Python a few lines below. This is useful since it's an ADT with both classes and values (Message.Quit is a value - you can't instantiate it).
This is possible today in Python, like this:
```
class MessageValue(Enum):
QUIT = "quit"
@dataclass
class Move:
x: int
y: int
@dataclass
class Write:
msg: str
@dataclass
class ChangeColor:
r: int
g: int
b: int
Message = MessageValue | Move | Write | ChangeColor
```
but it's verbose and disjointed.
(Here's how this would be used:
```
def process_message(m: Message) -> None:
match m:
case MessageValue.QUIT:
print("quit")
case Move(x, y):
print(f"move: {x} {y}")
case Write(msg):
print(f"write: {msg}")
case ChangeColor():
print("change color")
case _ as x:
assert_never(x)
```)
I propose adding some magic, so we get this instead:
```
class Message(Enum):
QUIT = "quit"
@dataclass
class Move:
x: int
y: int
@dataclass
class Write:
msg: str
@dataclass
class ChangeColor:
r: int
g: int
b: int
```
with the same semantics as `Message` in the first example. (The dataclasses are *inside* the Message enum.)
Given a Python Enum, type checkers already semantically treat it as a Union of its values. We extend this union to contain instances of classes defined inside. If backwards comp is an issue, we add a different base class in the enum module (so it'd be `Message(ADT)` instead of `Message(Enum)`.