You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Introduce a type for an unknown invariant generic param that behaves strictly #2169
This is the same issue as #1835, which was closed -- the given reason was that object can be used instead of Unknown. However, this is not the case. Consider:
if this should be callable and return object (that is, could be any Python object), then I think what you are looking for is what in the ty type-checker we call the "top materialization" of Foo[Any] -- that is, the infinite union of all possible specializations of Foo. In ty (with from ty_extensions import Top) you can spell this type as Top[Foo[Any]]. It has the behavior that T in all covariant positions becomes object, and in all contravariant positions becomes Never -- when you take out a T, it could be any Python object, and you aren't allowed to put in a T, because you don't know what type is allowed.
Note that if Foo were covariant in T (implies no T in contravariant position), then Top[Foo[Any]] is equivalent to Foo[object]. And if Foo were contravariant in T, it is equivalent to Foo[Never]. So you only really need a dedicated representation for this in this case of invariant generics.
I don't think we should use the name Unknown to represent this concept, because several existing Python type checkers already have a type named Unknown which is something different: it is equivalent to Any, but originates from a missing annotation rather than from an explicit Any annotation.
In a sense the type you are proposing is dual to Any -- it is "an unknown static type", but with the strictest possible behavior (nothing can be assigned to it, it can only be assigned to object) rather than the most forgiving possible behavior (as with Any).
I am curious what your concrete use case for this is. In ty we use this type internally to represent the effect of if isinstance(x, Foo) as an intersection -- but usually you want it to simplify out of the resulting intersection, because having an instance of Top[Foo[Any]] is typically not very useful.
My concrete usecase is when I have code that dynamically chooses different types based on data, e.g. if I am deserializing an object.
def make_foo(data: dict) -> Foo[Unknown]:
if data['type'] == 'str':
return Foo[str](...)
if data['type'] == 'int':
return Foo[int](...)
I like Foo[Unknown] more than Top[Foo[Any]] because Foo[Any] itself isn't quite correct, but I agree that another name would be better to avoid clashing with existing type checkers.
Or maybe even better: start a new discussion with a more specific idea. People seem to have pretty different visions of what an Unknown type should do and what it's good for.
Activity
carljm commentedon Feb 6, 2026
What behavior would you want from a third method:
if this should be callable and return
object(that is, could be any Python object), then I think what you are looking for is what in the ty type-checker we call the "top materialization" ofFoo[Any]-- that is, the infinite union of all possible specializations ofFoo. In ty (withfrom ty_extensions import Top) you can spell this type asTop[Foo[Any]]. It has the behavior thatTin all covariant positions becomesobject, and in all contravariant positions becomesNever-- when you take out aT, it could be any Python object, and you aren't allowed to put in aT, because you don't know what type is allowed.Note that if
Foowere covariant inT(implies noTin contravariant position), thenTop[Foo[Any]]is equivalent toFoo[object]. And ifFoowere contravariant inT, it is equivalent toFoo[Never]. So you only really need a dedicated representation for this in this case of invariant generics.I don't think we should use the name
Unknownto represent this concept, because several existing Python type checkers already have a type namedUnknownwhich is something different: it is equivalent toAny, but originates from a missing annotation rather than from an explicitAnyannotation.In a sense the type you are proposing is dual to
Any-- it is "an unknown static type", but with the strictest possible behavior (nothing can be assigned to it, it can only be assigned toobject) rather than the most forgiving possible behavior (as withAny).I am curious what your concrete use case for this is. In ty we use this type internally to represent the effect of
if isinstance(x, Foo)as an intersection -- but usually you want it to simplify out of the resulting intersection, because having an instance ofTop[Foo[Any]]is typically not very useful.vladfi1 commentedon Feb 7, 2026
My concrete usecase is when I have code that dynamically chooses different types based on data, e.g. if I am deserializing an object.
I like
Foo[Unknown]more thanTop[Foo[Any]]becauseFoo[Any]itself isn't quite correct, but I agree that another name would be better to avoid clashing with existing type checkers.srittau commentedon Feb 9, 2026
Please discuss any further ideas in the original issue. Closing this as a duplicate.
JelleZijlstra commentedon Feb 9, 2026
Or maybe even better: start a new discussion with a more specific idea. People seem to have pretty different visions of what an Unknown type should do and what it's good for.
carljm commentedon Feb 9, 2026
Yes -- I don't think the idea proposed here is actually the same as any of the prior proposals in #1835.
[-]Introduce an Unknown type[/-][+]Introduce a type for an unknown invariant generic param that behaves strictly[/+]