gvanrossum / patma

Pattern Matching
1.02k stars 65 forks source link

Sealed classes to facilitate ADT pattern #18

Open ilevkivskyi opened 4 years ago

ilevkivskyi commented 4 years ago

I propose to add a @typing.sealed class decorator that would do nothing at runtime, but indicate to static type checkers that all subclases must be defined in the same module. This will allow static checkers interpret such class as a union of all their children, so they can do static exhaustiveness checks. Effectively sealed classes together with dataclasses would provide nice support for algebraic data types pattern. See this (rather long) example:

from dataclasses import dataclass
from typing import sealed

@sealed
class Node:
    ...

class Expression(Node):
    ...

class Statement(Node):
    ...

@dataclass
class Name(Expression):
    name: str

@dataclass
class Operation(Expression):
    left: Expression
    op: str
    right: Expression

@dataclass
class Assignment(Statement):
    target: str
    value: Expression

@dataclasses
class Print(Statement):
    value: Expression

def dump(node: Node) -> str:
    match node:
    as Assignment(target, value):
        return f"{target} = {dump(value)}"
    as Print(value):
        return f"print({dump(value)})"
    as Operation(left, op, right):
        return f"({dump(left)} {op} {dump(right)})"
    # Error here because not all cases were checked!
Tobias-Kohn commented 4 years ago

Would this @sealed decorator not be a prime candidate to put into the utilities module #23?

It seems (other than for static type checkers) this has little influence on the match statements we are proposing. As the decorator has no effect within Python itself and is not mandatory, I do not see any reason to be against its introduction.

viridia commented 4 years ago

Can we mark this issue as accepted? Sorry if I'm playing project manager here (not my usual role, I assure you :))

viridia commented 4 years ago

Also, I wonder to what extent @typing.sealed can be used as an optimization hint: for example, if we know that the set of match patterns are distinct and non-overlapping, then I can see how you might be able to pre-generate a discrimination tree or possibly even a dispatch table (assuming no-one re-binds the names, not sure how you would get around that.)

gvanrossum commented 4 years ago

Bike shed: tying.sealed or matching_utils.sealed?

That optimization seems really advanced, we’re going to have our hands full just getting it to work.