I think the problem comes up more with invariant types than covariant types (if I remember terms correctly).

If the element type doesn't matter, then Sequence[object] is more type-safe than Sequence[Any] because it'll catch if you accidentally access something on the elements (copy/paste mistake, leftover debug code, etc). Since Sequence (and the other read-only iterables iirc) is covariant, you can pass any Sequence in and there isn't really a problem in practice.

But, that trick doesn't really work for MutableSequence because it's invariant. Passing [1, 2, 3] ( MutableSequence[int] ) to MutableSequence[object] is a type error. So, you're forced to do MutableSequence[Any] -- but now you've lost the stricter type checking from above.

The example given on the pytype issue tracker was:

def swap(items: MutableSequence[???], i: int, j: int):
  items[i], items[j] = items[j], items[i]

Which I supposed would generalize to something like, "You can't write a type-safe function that accepts a mutable generic" (a mutable generic should probably be invariant).

I suppose you could work around this by using T and returning T, but this again forces you into a bad design decision (returning a modified input is, at the least, questionable, since it can lead to confusing behavior/incorrect assumptions). Or I guess having a private method that does T->T, with a public wrapper that just accepts T. Or sprinkle casting around. But these really seem like playing games to accomplish what seems like something that should be relatively straight forward.

FWIW:

On Mon, Oct 19, 2020 at 10:14 AM Eric Traut <eric@traut.com> wrote:
This is a timely question. I just implemented a check in pyright for this condition because I found many cases where TypeVars were being used incorrectly within a function signature. I cleaned up a bunch of these cases within our code base thanks to this check.

I'm not sure what you mean by "Any swallows all errors" in the context of a `Sequence[Any]`. Presumably, the type checker would still treat that parameter as a Sequence even though it knows nothing about its contents. I don't see how the presence of a TypeVar would change that behavior. Could you elaborate?

If we think there is value is allowing a single instance of a TypeVar in a signature _and_ we can agree on a well-defined behavior for this case, then I think it makes sense to allow it. Otherwise, I think it's reasonable to emit an error to tell the user that they are using a language feature in a manner that is undefined.

Incidentally, when I implemented this check I noticed that it reported many errors within typeshed stdlib stubs. For example, `_SupportsLessThanT` appears only once in numerous signatures within builtins.pyi.

-Eric

--
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
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: richardlev@gmail.com