From 839b5f728e1e8d653ed288cbc743b7739e784cd9 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 30 Jan 2017 21:42:24 +0100 Subject: [PATCH 1/3] Clarify type erasure and instantiation of concrete collections --- pep-0484.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pep-0484.txt b/pep-0484.txt index 34595d86294..3a5404c1898 100644 --- a/pep-0484.txt +++ b/pep-0484.txt @@ -600,6 +600,17 @@ the type (class) of the objects created by instantiating them doesn't record the distinction. This behavior is called "type erasure"; it is common practice in languages with generics (e.g. Java, TypeScript). +Generic versions of concrete collections (except for built-in classes) +could be instantiated:: + + data = DefaultDict[int, bytes]() + +Note that one should not confuse static types and runtime classes. +Type is still erased in this case and the above expression is +just a shorthand for:: + + data = collections.delaultdict() # type: DefaultDict[int, bytes] + It is not recommended to use the subscripted class (e.g. ``Node[int]``) directly in an expression -- using a type alias instead is preferred. (First, creating the subscripted class, e.g. ``Node[int]``, has a runtime From 03602863ffcf52ed1abe00243f39e87700cdbee1 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 30 Jan 2017 23:17:20 +0100 Subject: [PATCH 2/3] Response to comments --- pep-0484.txt | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/pep-0484.txt b/pep-0484.txt index 3a5404c1898..0842c7c3b12 100644 --- a/pep-0484.txt +++ b/pep-0484.txt @@ -544,9 +544,8 @@ However, there are some special cases in the static typechecking context: Instantiating generic classes and type erasure ---------------------------------------------- -Generic types like ``List`` or ``Sequence`` cannot be instantiated. -However, user-defined classes derived from them can be instantiated. -Suppose we write a ``Node`` class inheriting from ``Generic[T]``:: +User-defined generic classes can be instantiated. Suppose we write +a ``Node`` class inheriting from ``Generic[T]``:: from typing import TypeVar, Generic @@ -583,38 +582,38 @@ the variable, e.g.:: a = Node() # type: Node[int] b = Node() # type: Node[str] -You can also create a type alias (see above) for a specific concrete -type and instantiate it, e.g.:: +Alternatively, you can instantiate a specific concrete type, e.g.:: # (continued from previous example) - IntNode = Node[int] - StrNode = Node[str] - p = IntNode() # Inferred type is Node[str] - q = StrNode() # Inferred type is Node[int] - r = IntNode('') # Error - s = StrNode(0) # Error - -Note that the runtime type (class) of p and q is still just ``Node`` --- ``IntNode`` and ``StrNode`` are distinguishable class objects, but + p = Node[int]() + q = Node[str]() + r = Node[int]('') # Error + s = Node[str](0) # Error + +Note that the runtime type (class) of ``p`` and ``q`` is still just ``Node`` +-- ``Node[int]`` and ``Node[str]`` are distinguishable class objects, but the type (class) of the objects created by instantiating them doesn't -record the distinction. This behavior is called "type erasure"; it is +record the distinction. This behavior is called "type erasure"; it is common practice in languages with generics (e.g. Java, TypeScript). -Generic versions of concrete collections (except for built-in classes) -could be instantiated:: +Generic versions of abstract collections like ``Mapping`` or ``Sequence`` +and generic versions of built-in classes -- ``List``, ``Dict``, ``Set``, +and ``FrozenSet`` cannot be instantiated. However, user-defined subclasses +thereof and generic versions of concrete collections can be instantiated:: data = DefaultDict[int, bytes]() Note that one should not confuse static types and runtime classes. -Type is still erased in this case and the above expression is +The type is still erased in this case and the above expression is just a shorthand for:: - data = collections.delaultdict() # type: DefaultDict[int, bytes] + data = collections.defaultdict() # type: DefaultDict[int, bytes] It is not recommended to use the subscripted class (e.g. ``Node[int]``) -directly in an expression -- using a type alias instead is preferred. -(First, creating the subscripted class, e.g. ``Node[int]``, has a runtime -cost. Second, using a type alias is more readable.) +directly in an expression -- using a type alias (e.g. ``IntNode = Node[int]``) +instead is preferred. (First, creating the subscripted class, +e.g. ``Node[int]``, has a runtime cost. Second, using a type alias +is more readable.) Arbitrary generic types as base classes From 56c063e4f4c1147340869b189805385caccc64db Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 30 Jan 2017 23:49:53 +0100 Subject: [PATCH 3/3] Response to latest comments --- pep-0484.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pep-0484.txt b/pep-0484.txt index 0842c7c3b12..b75c8d01406 100644 --- a/pep-0484.txt +++ b/pep-0484.txt @@ -592,14 +592,15 @@ Alternatively, you can instantiate a specific concrete type, e.g.:: Note that the runtime type (class) of ``p`` and ``q`` is still just ``Node`` -- ``Node[int]`` and ``Node[str]`` are distinguishable class objects, but -the type (class) of the objects created by instantiating them doesn't +the runtime class of the objects created by instantiating them doesn't record the distinction. This behavior is called "type erasure"; it is common practice in languages with generics (e.g. Java, TypeScript). Generic versions of abstract collections like ``Mapping`` or ``Sequence`` and generic versions of built-in classes -- ``List``, ``Dict``, ``Set``, -and ``FrozenSet`` cannot be instantiated. However, user-defined subclasses -thereof and generic versions of concrete collections can be instantiated:: +and ``FrozenSet`` -- cannot be instantiated. However, concrete user-defined +subclasses thereof and generic versions of concrete collections can be +instantiated:: data = DefaultDict[int, bytes]()