Skip to content

How to dispatch for generic types? #93

Open

Description

@Hong-Xiang

I'm trying to make some wraps for different "Tensor" like objects, and give them a unified interface. One typical use case unified shape function for np.ndarray and tf.Tensor, the problem is tf.Tensor's shape property does not return list/tuple object.

import tensorfolow as tf
import numpy as np
from typing import Generic, List, Optional, TypeVar

T = TypeVar('T')
class Tensor(Generic[T]):
    def __init__(self, data: T):
        self.data = data

@dispatch()
def shape(t: Tensor[np.ndarray]) -> List[int]:
    return list(t.data.shape)

@dispatch()
def shape(t: Tensor[tf.Tensor]) -> List[Optional[int]]:
    return t.data.shape.as_list()

To make things easier, we may first have an minimal example, can we have the following code work:

@dispatch()
def foo(xs: List[int]):
    return [x**2 for x in xs]

@dispatch()
def foo(xs: List[str]):
    return [x + '1' for x in xs]

foo([1,2,3]) # [1, 4,  9]
foo(['1', '2']) # ['11', '12']

I've noticed these problems:

  • Generic types in typing can not be used in issubclass or isinstance;
  • covariant/contravariant/invariant problem, this might be marked by TypeVar, but how to use it in multidipatch? (Julia seems has good solution for this)
  • TypeVar information is not kept after init, there might be no actual difference between different concrete types objects after instantiated, like:
from typing import Generic, TypeVar

T = TypeVar('T')
class D(Generic[T]):
    def __init__(self, data: T):
        self.data = data

d = D[int](1)
s = D[str]('s')
type(d) is type(s) # True

There might be much more problem than I noticed. A solution I can image is creating a new Generic metaclass, and let it produce truly concrete type when subscribed like Generic[T] (cache maybe needed).

IMO, type system might be not expressive enough in python, it might be ok if we don't use multidispatch. But it becomes somehow inconvenient if we use multidispatch heavily in our program.

I'm have not seriously used/learned type theory yet, this might completely a wrong issue.
So,

  • is this a "true" issue, or is this just a misunderstanding/wrong usage of Generic or multidispatch?
  • if it is a proper issue, do we have solution/work around for this?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions