jspahrsummers / adt

Algebraic data types for Python (experimental, not actively maintained)
MIT License
172 stars 14 forks source link

Named fields #19

Open jerbaroo opened 5 years ago

jerbaroo commented 5 years ago
@adt
class ExampleADT:
    EMPTY: Case
    INTEGER: Case[int]
    STRING_PAIR: Case[str, str]

First, I love what you are doing with this library. There is just one thing holding me back from using it. I would like to name the fields, rather than access them with positional indexing. Something like what I am showing below.

@adt
class ExampleADT:
    EMPTY: Case
    INTEGER: Case[int]
    STRING_PAIR: Case[foo: str, bar: str]

The accessor method could return a NamedTuple instead of just a Tuple.

def string_pair(self) -> Tuple[str, str]:
        # unpacks strings and returns them in a tuple
jspahrsummers commented 5 years ago

Thanks for reaching out, and for the feedback!

I too would really like to do something like this. Unfortunately, we are ultimately constrained by the syntax of the language and what is observable through mypy, so I'm not sure how to make the example as written (Case[foo: str, bar: str]) valid.

One workaround could be to define a separate type which names the fields you care about—e.g.:

class StringPair(NamedTuple):
  foo: str
  bar: str

@adt
class ExampleADT:
  STRING_PAIR: Case[StringPair]

… but I realize that's not ideal syntactically.

A possibility here could be to permit a "special" initial value for the field, which names the arguments—something like:

@adt
class ExampleADT:
  STRING_PAIR = NamedCase(foo: str, bar: str)

If our mypy plugin would be able to extract str, str from this, then we should still have enough type information to check that the Cases are being used correctly. I haven't thought about it a whole lot, though. 😄

If you or anyone would like to take a stab at something like this, I'd be happy to help and/or review the code—just let me know!