I'm not a fan of `Tensor[T, ...]` because it has confusing semantics.

Tensors will usually be typed as:

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

where `Tensor[np.float64, Literal[10], Literal[20]]` represents a 10x20 Tensor where each element has datatype `np.float64`. Let's say we want to represent a Tensor that has arbitrary shape.

+ `Tensor[np.float64, ...]` looks like it represents a Tensor of datatype np.float64 and arbitrary shape. But by analogy with the similar `Tuple[float, ...]`, it would have to represent any Tensor where all the *dimensions* are `np.float64`: `Tensor[np.float64, np.float64, np.float64]`, etc. That's not what we would expect for a Tensor.

+ To counter that, we might change the semantics of `Tensor[T, ...]`, to mean datatype T with arbitrary shape (i.e., `Tensor[T, Any, Any, Any]`, etc.), but that will be ambiguous for a class that has multiple unary generics like:

class Transformer(Generic[T_in, T_out, *Shape]): ...

# Is `T_out` int or Any?
x: Transformer[int, ...]

New syntax like Transformer[int, str, ...] seems even more confusing.

+ The only remaining use afaik would be `Tensor[Any, ...]` to represent a Tensor where all parameters are Any. Given that `x: Tensor` already represents this, it doesn't feel worth adding fresh syntax to express the same.

In contrast, `Tensor[np.float64, *Tuple[Any, ...]]` expresses the fact that the datatype is `np.float64` but the shape can be anything. `Transformer[A, B, *Tuple[Any, ...]]` works for the other case. We can also state that the dimension types have to be int: `Tensor[np.float64, *Tuple[int, ...]]` to represent `Tensor[np.float64, int, int, int]`, etc.

I completely agree that the syntax is verbose and frankly not very pretty :) (TypeScript has a nicer `Tensor[float, ...any[]]` syntax.) That seems fine given that we don't really want to encourage this.

Overall, I see two options:
+ No explicit syntax for unbounded Tensors: We just have `x: Tensor` to support gradual typing as of PEP 646 and we can add unbounded Tensors in follow-up PEPs. Typecheckers would be free to treat `Float32Array = Array[np.float32, *Shape]; x: Float32Array` as `x: Array`, thereby making all parameters `Any`. This seems like the simplest option right now.

+ Explicit syntax where we substitute `Tuple[Any, ...]` for `Ts`: This would complicate an already heavy PEP, but would allow us to precisely express the fact that the shape can be anything.

On Sun, Feb 21, 2021 at 8:28 AM Eric Traut <eric@traut.com> wrote:
Hmm, I'm not a fan of `Tensor[*Tuple[Any, ...]`. That's really verbose and inconsistent with existing standards. And it would require all type checkers to add support for open-ended non-homogenous tyes, which would be a heavy lift. Let's save that for another future PEP.

I was proposing that we simply extend the PEP 484 tensor convention to all variadic generic types. So this would be `Tensor[Any, ...]`.

Eric Traut
Contributor to Pyright & Pylance
Microsoft Corp.
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
Member address: gohanpra@gmail.com

S Pradeep Kumar