-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
model ADTs with dataclasses and union types
- Loading branch information
Nathaniel May
committed
Oct 25, 2021
1 parent
f4268e4
commit 821d65b
Showing
1 changed file
with
35 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,42 @@ | ||
|
||
from dataclasses import dataclass | ||
from typing import NoReturn, Union | ||
|
||
class Singleton: | ||
__instance = None | ||
@staticmethod | ||
def getInstance(): | ||
""" Static access method. """ | ||
if Singleton.__instance == None: | ||
Singleton() | ||
return Singleton.__instance | ||
def __init__(self): | ||
""" Virtually private constructor. """ | ||
if Singleton.__instance != None: | ||
raise Exception("This class is a singleton!") | ||
else: | ||
Singleton.__instance = self | ||
|
||
# common trick for getting mypy to do exhaustiveness checks | ||
# will come up with something like `"assert_never" has incompatible type` | ||
# if something is missing. | ||
def assert_never(x: NoReturn) -> NoReturn: | ||
raise AssertionError("Unhandled type: {}".format(type(x).__name__)) | ||
|
||
# All classes that inherit from this one should be defined in this file. | ||
class BaseEvent(): | ||
pass | ||
|
||
# TODO dummy class | ||
@dataclass(frozen=True) | ||
class OK: | ||
result: int | ||
|
||
class StartParse(BaseEvent): | ||
pass | ||
|
||
# TODO dummy class | ||
@dataclass(frozen=True) | ||
class Failure: | ||
msg: str | ||
|
||
|
||
# using a union instead of inheritance means that this set cannot | ||
# be extended outside this file, and thus mypy can do exhaustiveness | ||
# checks for us. | ||
Event = Union[OK, Failure] | ||
|
||
|
||
# function that translates any instance of the above event types | ||
# into its human-readable message. | ||
# | ||
# This could instead be implemented as a method on an ABC for all | ||
# above classes, but this at least puts all that logic in one place. | ||
def humanMsg(r: Event) -> str: | ||
if isinstance(r, OK): | ||
return str(r.result) | ||
elif isinstance(r, Failure): | ||
return "Failure: " + r.msg | ||
else: | ||
assert_never(r) |