-
-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable Supports[]
to refer to multiple typeclasses
#206
Comments
@eganjs great idea! I will do this in several days, I am preparing a new release right now! 👍 |
Awesome @sobolevn I look forward to using it in action! |
So! I'm on it! Let's see what we can possibly do here.
Let's say that we have this code: from classes import typeclass, AssociatedType, Supports
class A(AssociatedType):
...
@typeclass(A)
def a(instance) -> str:
...
@a.instance(int)
def _a_int(instance: int) -> str:
...
@a.instance(str)
def _a_str(instance: str) -> str:
...
# =====
class B(AssociatedType):
...
@typeclass(B)
def b(instance) -> str:
...
@b.instance(int)
def _b_int(instance: int) -> str:
...
@b.instance(list)
def _b_list(instance: lost) -> str:
... Next thing, we want a type that This must work: number: int
a: Supports[A] = number
b: Supports[B] = number
ab: Supports[A, B] = number
a = ab
b = ab And this should be an error, because ab = a
ab = b So, it feels like this should work: class A: ...
class B: ...
class AB(A, B): ... But, then we have a problem. Because we would have to track all types and their subtypes and inject these new intersection types everywhere. I will need to think about other approaches. |
Looks like this might be a way to go: from typing_extensions import Protocol
class A(Protocol):
_classes_supports_A: 'A'
class B(Protocol):
_classes_supports_B: 'B'
class AB(Protocol, A, B):
...
# This is an emulation of `@some.instance(Number)`
# Consider `Number` as the instance type we are going to work with.
class Number(object):
_classes_supports_A: 'A'
_classes_supports_B: 'B'
n: Number
a: A = n
b: B = n
ab: AB = n
a1: A = AB
# Incompatible types in assignment (expression has type "Type[AB]", variable has type "A")
b1: B = AB
# Incompatible types in assignment (expression has type "Type[AB]", variable has type "B") |
Ok, this is hard. I am going to release it later, not in the closest version. |
Here's my attempt: from typing_extensions import Protocol
from typing import Union, TypeVar
from classes import AssociatedType
_T = TypeVar('_T')
class Supports(Protocol[_T]):
__classes_supports: _T
class A(AssociatedType):
...
class B(AssociatedType):
...
class C(AssociatedType):
...
# Real data types:
# It will be used in `@some.instance(HasA)`
class HasA(object):
__classes_supports: A
class HasB(object):
__classes_supports: B
class HasAB(object):
__classes_supports: Union[A, B]
class HasABC(object):
__classes_supports: Union[A, B, C]
a: HasA
b: HasB
ab: HasAB
sup_a: Supports[A]
sup_b: Supports[B]
sup_ab: Supports[Union[A, B]]
sup_a = a # ok
sup_b = b # ok
sup_ab = ab # ok
sup_ab = a # fail
sup_ab = b # fail
sup_abc: Supports[Union[A, B, C]]
sup_ab = sup_abc # fails, is it correct? The only problem for me right now: sup_abc: Supports[Union[A, B, C]]
sup_ab = sup_abc # fails, is it correct? If some typeclass supports I think that to achieve this I need to fallback to individual props 😞 |
Ok, seems that this works: from typing import Union, Generic, TypeVar
T = TypeVar('T', contravariant=True)
class Supports(Generic[T]):
...
class A:
...
class B:
...
def some_a(instance: Supports[A]):
...
def some_b(instance: Supports[B]):
...
def some_ab(instance: Supports[Union[A, B]]):
...
a: Supports[A]
b: Supports[B]
ab: Supports[Union[A, B]]
some_a(a) # ok
some_a(b) # incompatible type "Supports[B]"; expected "Supports[A]"
some_a(ab) # ok
some_b(a) # incompatible type "Supports[A]"; expected "Supports[B]"
some_b(b) # ok
some_b(ab) # ok
some_ab(a) # incompatible type "Supports[A]"; expected "Supports[Union[A, B]]"
some_ab(b) # incompatible type "Supports[B]"; expected "Supports[Union[A, B]]"
some_ab(ab) # ok
a = ab # ok
b = ab # ok
ab = a # error
ab = b # error My plan:
|
See #250 |
This is similar to #83 and python/typing#213, but offers the advantages of composability and conciseness.
I'd be willing to have a go at implementing this but I'm not very familiar with mypy plugins (where I suspect most of the work would be required).
The text was updated successfully, but these errors were encountered: