typing icon indicating copy to clipboard operation
typing copied to clipboard

Consider adding a "TopLevel" keyword that stands in for the top level bound of a corresponding type variable

Open NeilGirdhar opened this issue 2 years ago • 6 comments

Summary

Please consider a new typing keyword that stands in for the top level type of a corresponding type variable.

Motivation

Consider a test here and the corresponding definition of DistributionInfo here. The test loses all typing information because I used DistributionInfo[Any, Any, Any]. So if I want typing information, I have to use:

def test_flatten(generator: Generator,
                 distribution_info: DistributionInfo[NaturalParametrization[ExpectationParmetrization, JaxComplexArray],
                                                     ExpectationParametrization[NaturalParmetrization],
                                                     NumpyComplexArray]) -> None:

I would much rather just do

def test_flatten(generator: Generator,
                 distribution_info: DistributionInfo[TopLevel, TopLevel, TopLevel]) -> None:

It's not just shorter, but it reduces churn if the type definitions change. Note that TopLevel is recursive (it chooses the top level of the nested types too).

NeilGirdhar avatar May 04 '23 20:05 NeilGirdhar

Isn't this redundant with defaults from PEP-696?

JelleZijlstra avatar May 04 '23 21:05 JelleZijlstra

Isn't this redundant with defaults from PEP-696?

It's really similar, yeah. But even if I were to specify defaults, one would still have to follow the recursive definitions of nested type variables. So the default of the DistributionInfo variables would have to incorporate the top level types of NaturalParametrization's type variables, and the top level types of their nested type variables, etc.

And not all classes are going to want to specify defaults. If dict were annotated class dict[T: Hashable, U: Any](..., and without defaults, then it might be nice to type dict[TopLevel, TopLevel] as shorthand for dict[Hashable, Any]?

In other words, whereas Any does as little type checking as possible, TopLevel preserves as much as possible without specifying anything new.

NeilGirdhar avatar May 04 '23 21:05 NeilGirdhar

In your example, the DistributionInfo has three type parameters, and all of them are invariant. If you supply a concrete type argument (whether explicitly, implicitly with a default type a'la PEP 696, or through a mechanism like the proposed TopLevel shorthand), callers of test_flatten would not be able to pass an argument whose type arguments are not exact matches. That's the nature of invariance. This restriction doesn't apply to DistributionInfo[Any, Any, Any] because Any is exempt from invariance checks.

Your example would make more sense if the three type parameters for DistributionInfo (and all of the other generic classes in your example) were covariant. The TopLevel mechanism would then work, but it would add no new value other than brevity. Since this isn't a pattern that occurs often (especially if it's applicable only for covariant type parameters), I think it would be hard to motivate the introduction of a new addition to the type system.

erictraut avatar May 04 '23 21:05 erictraut

Your example would make more sense if the three type parameters for DistributionInfo (and all of the other generic classes in your example) were covariant.

Thanks for explaining, but that's not going to work because of the definition of DistirbutionInfo. I'm just curious why can't type checkers figure out here that p has type ExpectationParametrization[Any]? I realize that EP is bound to Any, but given that EP has an upper bound of ExpectationParametrization[Any], is there no way to deduce such an upper bound for p?

NeilGirdhar avatar May 05 '23 09:05 NeilGirdhar

Related? https://github.com/python/typing/issues/912

parched avatar Jul 22 '23 12:07 parched

@parched Yes, related! I wish that hadn't been closed. It would be nice to contribute to that thread.

NeilGirdhar avatar Jul 22 '23 16:07 NeilGirdhar