Skip to content

Instantly share code, notes, and snippets.

@edelooff
Last active July 1, 2021 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edelooff/02050858d72a3dad6c0031db08ce5ae8 to your computer and use it in GitHub Desktop.
Save edelooff/02050858d72a3dad6c0031db08ce5ae8 to your computer and use it in GitHub Desktop.
Playing with structural typing
from __future__ import annotations
from dataclasses import dataclass
from typing import Generic, Optional, Protocol, TypeVar
CT = TypeVar("CT", bound="Comparable")
class Comparable(Protocol):
def __lt__(self: CT, other: CT) -> bool:
...
class NodeProto(Protocol[CT]):
value: CT
@property
def left(self) -> Optional[NodeProto[CT]]:
...
@property
def right(self) -> Optional[NodeProto[CT]]:
...
Node = NodeProto[Comparable]
@dataclass
class BinaryNode(Generic[CT]):
value: CT
left: Optional[BinaryNode[CT]] = None
right: Optional[BinaryNode[CT]] = None
@dataclass
class BN2(Generic[CT]):
value: CT
left: Optional[BN2[CT]] = None
right: Optional[BN2[CT]] = None
def main() -> None:
n1: NodeProto = BinaryNode("foo")
# error: Missing type parameters for generic type "NodeProto"
# caused by making Protocol generic over CT
n1b: Node = BinaryNode("foo") # Node is an alias for NodeProto[Comparable]
n2 = BinaryNode("foo") # n2 has type BinaryNode[str]
n2.left = BinaryNode(1)
# error: Argument 1 to "BinaryNode" has incompatible type "int"; expected "str"
# caught by making Protocol generic over CT
n3 = BinaryNode(object())
# error: Value of type variable "CT" of "BinaryNode" cannot be "object"
n4: BinaryNode[Comparable] = BinaryNode("stringtyped")
n4.left = BinaryNode(2) # allowed: both types are comparable, even if different :(
n4.right = BinaryNode(object())
# error: Argument 1 to "BinaryNode" has incompatible type "object";
# expected "Comparable"
n5 = BinaryNode(5)
n5.left = BinaryNode(3)
n5.right = BN2(7)
# error: Incompatible types in assignment (expression has type "BN2[int]",
# variable has type "Optional[BinaryNode[int]]")
n6: BinaryNode[object]
# error: Type argument "builtins.object" of "BinaryNode"
# must be a subtype of "trees.Comparable"
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment