> I  just realized there's a situation where bare generic types are important: when evolving a codebase, making certain types that weren't generic before generic.

Yeah, this is exactly the situation that I imagine we'll be in with array types: hopefully (at least in my personal ideal world) we'd be able to persuade library authors to make the existing types like `tf.Tensor`, `np.ndarray` etc generic in shape.

> So I'm not in favor of saying that `Tensor` is the only legitimate way to specify "a `Tensor` whose type arguments can be anything". If we think that concept is needed, then we should support `Tensor[Any, ...]`.

The idea I had in mind worked the opposite way around: it's less that `Tensor` should be the only legitimate way of specifying arbitrary parameters, and more that arbitrary type parameters should be what `Tensor` means, in order to support gradual typing if `Tensor` becomes generic. For cases where the user wants to deliberately specify "a Tensor of any shape", I'm imagining they'd do something like:

```
Shape = TypeVarTuple('Shape')

def pointwise_multiply(x: Tensor[*Shape], y: Tensor[*Shape]) -> Tensor[*Shape]: ...
```

This would specify that `x` and `y` can be an arbitrary shape, but they should be the same shape, and that shape would also be the shape of the returned `Tensor`.

(If the user instead wanted to say that `x` and `y` could be arbitrary, different shapes, they would use different `TypeVarTuple` instances. This would, of course, potentially rely on the type-checker being ok with only a single usage of a `TypeVarTuple` in a function signature. From a quick skim of the analogous discussion about `TypeVar` in typing-sig a few months ago, I get the impression the jury is still out on whether that should be an error. But luckily, I think this use case is likely to be rare enough that we can ignore that issue for now. I can't think of any specific functions off the top of my head which would take arbitrary arrays of different shapes.)

> I consider it a bug in mypy that it accepts `Tensor[()]`.

Interesting - do you say this mainly on the basis that since it causes a runtime error, it should also be a type error? To me, it feels more intuitive that this shouldn't be an error, based on the argument that `Tensor` behaves like `Tensor[Any]`, and (without thinking about it too hard - i.e. not thinking about how the variance should work) `Tensor[Any]` seems like it should be compatible with `Tensor[()]`.

> Interestingly, mypy does emit an error if you try to pass other illegal values as a type argument (like `Tensor[0]`).

I was surprised by this, so I did a bit more experimenting. Mypy does indeed error for me too on `Tensor[0]`, but that was only because of the lack of `Literal`. The following two examples do type-check fine for me with Mypy:

```
x: Tensor[Literal[0]] = Tensor()
foo(x)

x: Tensor[int] = Tensor()
foo(x)
```

Having said all that -

> I don't think we should promote the use of "bare" generic types — those with no type arguments. That's typically indicative of an error on the programmer's part. Pyright accepts them, but it flags it as an error when "strict" mode is enabled. 

This makes a lot of sense to me and I definitely think that such a flag should continue to exist and be prominently advertised. With the case of `Tensor`, too, it would be super helpful to have the type-checker error with "Hey, you haven't specified what shape this `Tensor` should be!"



On Thu, 4 Feb 2021 at 18:15, Guido van Rossum <guido@python.org> wrote:
On Wed, Feb 3, 2021 at 12:41 PM Guido van Rossum <guido@python.org> wrote:
On Wed, Feb 3, 2021 at 11:15 AM Eric Traut <eric@traut.com> wrote:
I don't think we should promote the use of "bare" generic types — those with no type arguments. That's typically indicative of an error on the programmer's part. Pyright accepts them, but it flags it as an error when "strict" mode is enabled. This check has been really useful in helping developers to fix problems in their code, and I don't want to water it down. So I'm not in favor of saying that `Tensor` is the only legitimate way to specify "a `Tensor` whose type arguments can be anything". If we think that concept is needed, then we should support `Tensor[Any, ...]`. As I said, adding support for open-ended tuples will add yet more complexity to the specification and implementation of this PEP, but maybe it's required to meet all of the intended use cases.

Agreed. I think they are mostly a legacy feature.

I just realized there's a situation where bare generic types are important: when evolving a codebase, making certain types that weren't generic before generic. An real-world example is the stdlib Queue type -- this started its life as a non-generic class (in typeshed) and at some point it was made generic. During the time it was non-generic, user code was annotated with things like `(q: Queue)`, and it would be a problem to fault all that code immediately as being non-compliant. So the interpretation of this as `Queue[Any]` makes sense. (Of course a flag exists to make this an error, for users who want to update all their code to declare the item type of their queues.)

So it's not that bare generics themselves are a legacy feature -- but the feature is primarily important for situations where legacy code is being checked.

--
--Guido van Rossum (python.org/~guido)
_______________________________________________
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: mrahtz@google.com