From 73853822f3de1629e17774c29667fcad539363ca Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 24 Jan 2025 15:51:47 -0800 Subject: [PATCH 1/3] PEP 747: a few suggested updates --- peps/pep-0747.rst | 57 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/peps/pep-0747.rst b/peps/pep-0747.rst index e4ce2a0ee65..d9f6fc10337 100644 --- a/peps/pep-0747.rst +++ b/peps/pep-0747.rst @@ -200,14 +200,20 @@ that represent a type assignable to ``str | None``:: err1: TypeForm[str | None] = str | int # Error err2: TypeForm[str | None] = list[str | None] # Error -By this same definition, ``TypeForm[Any]`` describes a type form object -that represents the type ``Any`` or any type that is assignable to ``Any``. -Since all types in the Python type system are assignable to ``Any``, -``TypeForm[Any]`` describes the set of all type form objects -evaluated from all valid type expressions. +By this same definition, ``TypeForm[object]`` describes a type form object that +represents the type ``object`` or any type that is assignable to ``object``. +Since all types in the Python type system are assignable to ``object``, +``TypeForm[object]`` describes the set of all type form objects evaluated from +all valid type expressions. -The type expression ``TypeForm``, with no type argument provided, is -equivalent to ``TypeForm[Any]``. +The type expression ``TypeForm``, with no type argument provided, signals that +the expression assigned to this annotated type should be interpreted as a type +expression, resulting in a ``TypeForm`` type, but the type parameter of that +``TypeForm`` type should be inferred from the type expression. For example, +these two assignments are equivalent:: + + tf1: TypeForm = int | None + tf2: TypeForm[int | None] = int | None Implicit ``TypeForm`` Evaluation @@ -289,7 +295,7 @@ This explicit syntax serves two purposes. First, it documents the developer's intent to use the value as a type form object. Second, static type checkers validate that all rules for type expressions are followed:: - x4 = type(int) # No error, evaluates to "type[int]" + x4 = type(int) # No error, evaluates to "type[type]" x5 = TypeForm(type(int)) # Error: call not allowed in type expression @@ -533,21 +539,26 @@ of ``type``. Treat ``type[T]`` as a subtype of ``TypeForm[T]`` ------------------------------------------------- -It was suggested that type ``type[T]`` should be considered a subtype -of ``TypeForm[T]``. This was ultimately rejected because there are ways to -create an object of type ``type[T]`` that does not encode a valid type expression. -For example, the expression ``type[1]`` is not a valid type expression. Likewise, -the expression ``type[S]`` is not a valid type expression if ``S`` is an -out-of-scope type variable. This same argument applies to other special forms -like objects of type ``UnionType``, which may or may not encode a valid type -expression. Rather than carving out a special case for ``type[T]`` that would -allow for potential unsoundness, it was decided to treat all type forms -consistently. Therefore, ``type[T]`` is not considered a subtype of ``TypeForm[T]``. - -It was also pointed out that the expression ``C | C`` (where ``C`` is a class -object) is a valid type expression - and therefore a valid ``TypeForm``, -but its runtime type form encoding is an instance of ``UnionType`` and -therefore is not compatible with ``type[C]``. +It was suggested that type ``type[T]`` should be considered a subtype of +``TypeForm[T]``. This is intuitive because, given a class ``C``, the expression +``C`` both evaluates at runtime to the type object ``C`` (which inhabits the +type ``type[C]``), and is also a valid type expression spelling the type ``C`` +(therefore also inhabits the type ``TypeForm[C]``). + +The problem is that there are other expressions (for example, +``C().__class__``), which also evaluate to the class object ``C``, but are not +valid type expressions spelling the type ``C``, therefore should not inhabit +``TypeForm[C]``. In order to maintain consistency that ``TypeForm`` types may +only originate in valid type expressions, we say that ``type[T]`` is not a +subtype of ``TypeForm[T]``. (This implies that the type system considers the +objects resulting from ``C`` and ``C().__class__`` to be distinguishable, in +that the former is a valid ``TypeForm`` and the latter is not, even though they +are identical at runtime.) + +``TypeForm[T]`` is also not a subtype of ``type[T]``, because the expression +``C | C`` (where ``C`` is a class object) is a valid type expression - and +therefore a valid ``TypeForm``, but its runtime type form encoding is an +instance of ``UnionType`` and therefore does not inhabit ``type[C]``. If a function wishes to indicate that it accepts values of type ``TypeForm[T]`` _and_ ``type[T]``, the parameter can simply be annotated with a union of these From e8c257627b77012de254f3b15ed5bd020a3a2819 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 24 Jan 2025 16:00:48 -0800 Subject: [PATCH 2/3] simplify example --- peps/pep-0747.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0747.rst b/peps/pep-0747.rst index d9f6fc10337..13c868bed70 100644 --- a/peps/pep-0747.rst +++ b/peps/pep-0747.rst @@ -295,9 +295,9 @@ This explicit syntax serves two purposes. First, it documents the developer's intent to use the value as a type form object. Second, static type checkers validate that all rules for type expressions are followed:: - x4 = type(int) # No error, evaluates to "type[type]" + x4 = type(1) # No error, evaluates to "type[int]" - x5 = TypeForm(type(int)) # Error: call not allowed in type expression + x5 = TypeForm(type(1)) # Error: call not allowed in type expression Assignability From ac65ab91beafd8080180acdb80b3135cb83fd651 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 24 Jan 2025 16:08:09 -0800 Subject: [PATCH 3/3] TypeForm means TypeForm[Any] --- peps/pep-0747.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/peps/pep-0747.rst b/peps/pep-0747.rst index 13c868bed70..50ed2f723f7 100644 --- a/peps/pep-0747.rst +++ b/peps/pep-0747.rst @@ -206,14 +206,12 @@ Since all types in the Python type system are assignable to ``object``, ``TypeForm[object]`` describes the set of all type form objects evaluated from all valid type expressions. -The type expression ``TypeForm``, with no type argument provided, signals that -the expression assigned to this annotated type should be interpreted as a type -expression, resulting in a ``TypeForm`` type, but the type parameter of that -``TypeForm`` type should be inferred from the type expression. For example, -these two assignments are equivalent:: - - tf1: TypeForm = int | None - tf2: TypeForm[int | None] = int | None +``TypeForm[Any]`` describes a ``TypeForm`` type whose type argument is not +statically known, and is thus assignable both to and from any other +``TypeForm`` type (because ``Any`` is assignable both to and from any type.) + +The type expression ``TypeForm``, with no type argument provided, is +equivalent to ``TypeForm[Any]``. Implicit ``TypeForm`` Evaluation