On Wed, Dec 23, 2020 at 3:02 AM Matthew Rahtz via Typing-sig <typing-sig@python.org> wrote:
Thank you for sponsoring this, Guido, and for the thorough review!

You're welcome.

> I wonder why the proposal left out `Union[*Ts]`.

Ah, yes, great point. I'll add a section on that.

Looking forward to that.
> I'm not sure that `Tensor[T1, T2, ...]` is the be-all and end-all of tensor types (e.g. where would you put the data type of numpy arrays?) but maybe that can be handled by just adding one non-variadic type variable (a complete example would be nice though).

This has been on the back of my mind too. Adding a single additional non-variadic type variable is how I was imagining it would work too, though there are still some details to work out (e.g. ideally it should be optional so that people can choose what level of type verbosity they want to go with). I'll add a section trying to figure this out.

Making it optional would be complicated, given that the rest is variadic. Maybe a future PEP could use keyword indexing (PEP 637) but for now that's not an option yet.
The other thing that's still unresolved is how we handle access to individual types - needed so that we can provide overloads of shape-manipulating operations. (I'm assuming that overloads are the way to go here, at least for the time being. In an ideal world we would be able to express the resulting shapes directly as a function of the arguments, but I don't think that'll be possible without fully dependent typing).

Actually, Alfonso Castaño has quietly been working on a way to express this. I believe you know him?
My initial idea was to do this using "class overloads":

class Tensor(Generic[*Shape]): ...

class Tensor(Generic[Axis1, Axis2]):
  def transpose(self) -> Tensor[Axis2, Axis1]: ...

class Tensor(Generic[Axis1, Axis2, Axis3]):
  def transpose(self) -> Tensor[Axis3, Axis2, Axis1]: ...

But you're right in calling this out in the draft doc as non-trivial. It's also very verbose, requiring a whole separate class for each possible instantiation.

I think it would be best to drop that idea from this PEP.
Instead, perhaps the following would suffice?

class Tensor(Generic[*Shape]):

  def transpose(self: Tensor[Axis1, Axis2]) -> Tensor[Axis2, Axis1]: ...
  def transpose(self: Tensor[Axis1, Axis2, Axis3]) -> Tensor[Axis3, Axis2, Axis1]: ...

This is similar to the following example, which already seems to type-check properly in mypy:

class C(Generic[T]):

  def f(self: C[int], x) -> int:
    return x

  def f(self: C[str], x) -> str:
    return x

Yes, that sounds manageable.
I'd welcome other suggestions, though!

In any case, I'll continue cleaning up the doc as suggested, moving discussion of meatier issues to this thread for posterity, and post here once I think the doc is done.

Let me know how I can help. I am subscribed to the peps repo so when you send a PR there it will automatically notify me.

--Guido van Rossum (python.org/~guido)