> IntTuple = Tuple[int, *Ts]> As this example shows, all type parameters passed to the alias are bound to the type variable tuple. If no type parameters are given, or if an explicitly empty list of type parameters are given, type variable tuple in the alias is simply ignored:
>
> # Both equivalent to Tuple[int]
> IntTuple
> IntTuple[()]
Sorry, I had missed this example in the latest PEP update. I agree that x: IntTuple
should not be treated as IntTuple[()]
.
To be consistent with unparameterized Tensor
we should treat `x: IntTuple`
as an arbitrary-shaped Tuple, not as `IntTuple[()]
`. A generic alias with a free `*Ts` should be treated just as a `class IntTupleClass(BaseClass[int, *Ts], Generic[*Ts])`. In the latter case, x: IntTupleClass
would be treated as an arbitrary-shaped variadic. The unparameterized alias should behave the same way.
> In my opinion, omitting a type argument for a variadic type parameter should imply `Tuple[Any, ...]`. That's consistent with how `Tuple` works.
> If the type alias is concatenating other types with the variadic type var into a tuple, then the entire tuple should become a `Tuple[Any ...]`.
I think we agree about this. If we had the *Tuple[Any, ...]
syntax we would replace Ts
to get Tuple[int, *Tuple[Any, ...]]
, but since we're not adding this syntax in this PEP, we can keep it simple and just fall back to Tuple[Any, ...]
as a whole.
> The proposal is effectively saying "the type system supports open-ended variadic generics, but the only way to specify them is to use a syntax that we want to discourage".
That's partially true. The type system supports arbitrary-shaped variadics to the very limited extent that it won't complain about passing Tensor[int, str]
to Tensor
or vice versa. Even this is only in the PEP to support pre-existing code. A typechecker could comply with the PEP by special-casing unparameterized variadic classes and aliases, without implementing open-ended variadic generics.
> The first option (no explicit syntax) doesn't address my primary concern. It means that there's no way for a type checker to distinguish between "I forgot to add (or haven't gotten around to adding) type arguments" and "I explicitly and intentionally mean `Tensor[Any, ...]`.
> In its strictest mode, pyright complains about both `Ndim` and `Shape` missing type arguments. It's a common mistake for developers to forget type arguments on generic types, so this is an important error. You can fix the problem with `Ndim` by changing it to `Ndim[Any]`, but you can't do the same with `Shape` because `Shape[Any]` would imply a single dimension for the variadic.
Ah, I see. In your strictest mode, you want to (a) warn users when they inadvertently use an unparameterized Tensor but (b) not warn them when they explicitly denote something as having arbitrary shape.
I can't think of a good alternative solution. The problem is that `Tensor[Any, ...]` doesn't seem to be on the road to precise future syntax like `Tensor[np.float64, *Tuple[Any, ...]]`. And we'd have to forbid `Tensor[int, ...]`, `Tensor[T, ...]`, etc. because of the problems mentioned earlier.
How about making `Tensor[Any, ...]` a separate PEP? We could bikeshed other possibilities like `Tensor[...]` that disallow using `int`. We could also judge whether the new syntax is worth the niche but important use case. (And we wouldn't have to add typing.py support for it as part of PEP 646)