Last active
July 25, 2019 16:35
-
-
Save feuGeneA/5a217c18b245364e0ef01a6784f86844 to your computer and use it in GitHub Desktop.
More brainstorming on types for mesh simulation engine options
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
"""More brainstorming on types for mesh simulation engine options.""" | |
# the following comment was taken from p2p_incentives/example.py: | |
# Any option choice is a dictionary. It must contain a key "method," to | |
# specify which implementation function to call. The rest entries, if any, | |
# are the parameters specific to this implementation that will be passed to | |
# the function. | |
# This comment could be formally specified in code as: | |
from mypy_extensions import TypedDict | |
class Option(TypedDict): | |
"""An option choice.""" | |
method: str # which implementation function to call | |
# However, that doesn't really help us like I thought it would, because a class | |
# inheriting from Option cannot redefine the type of an attribute. That is, we | |
# would like to say: | |
# | |
# class Preference(Option): | |
# method = 'Passive' | |
# | |
# but then mypy says 'Cannot overwrite TypedDict field "method" while | |
# extending'. So maybe the multi-level TypedDict inheritance idea isn't so | |
# great after all. | |
# But I did discover Literal Types in mypy, described in detail at | |
# https://mypy.readthedocs.io/en/stable/literal_types.html , which we can use | |
# like this: | |
from typing_extensions import Literal # requires `pip install typing-extensions` | |
class Preference(TypedDict): | |
"""Preferences for neighbors.""" | |
method: Literal['Passive', 'SomeOtherMethodThatsNotPassive'] | |
# this says that method is a literal string that must have one of those values | |
# ('Passive', or the other one). That is, | |
# | |
# preference = Preference(method='RogueMethod') | |
# | |
# results in mypy saying "Incompatible types". | |
# here's how we would use this: | |
PREFERENCE: Preference = Preference(method='Passive') | |
# And here's an example of using this technique with an option whose method has | |
# parameters: | |
class Share(TypedDict): | |
"""How to determine the orders to share with neighbors.""" | |
method: Literal[ | |
'AllNewSelectedOld', | |
'SomeOtherMethodThatsNotAllNewSelectedOld' | |
] | |
class AllNewSelectedOld(Share): | |
max_to_share: int | |
old_share_prob: float | |
SHARE: Share = AllNewSelectedOld( | |
method='AllNewSelectedOld', | |
max_to_share=5000, | |
old_share_prob=0.5 | |
) | |
# Overall I like this approach, despite the annoying redundancy in having to | |
# specify method='AllNewSelectedOld' in the value declaration. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment