python-peps/pep-0695/index.html

1707 lines
160 KiB
HTML
Raw Permalink Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 695 Type Parameter Syntax | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0695/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 695 Type Parameter Syntax | peps.python.org'>
<meta property="og:description" content="This PEP specifies an improved syntax for specifying type parameters within a generic class, function, or type alias. It also introduces a new statement for declaring type aliases.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0695/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="This PEP specifies an improved syntax for specifying type parameters within a generic class, function, or type alias. It also introduces a new statement for declaring type aliases.">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 695</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 695 Type Parameter Syntax</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Eric Traut &lt;erictr at microsoft.com&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/thread/BB2BGYJY2YG5IWESKGTAPUQL3N27ZKVW/">Typing-SIG thread</a></dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Topic<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../topic/typing/">Typing</a></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">15-Jun-2022</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.12</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/thread/BB2BGYJY2YG5IWESKGTAPUQL3N27ZKVW/" title="Typing-SIG thread">20-Jun-2022</a>,
<a class="reference external" href="https://discuss.python.org/t/pep-695-type-parameter-syntax/21646" title="Discourse thread">04-Dec-2022</a></dd>
<dt class="field-even">Resolution<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-695-type-parameter-syntax/21646/92">Discourse message</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#points-of-confusion">Points of Confusion</a></li>
</ul>
</li>
<li><a class="reference internal" href="#summary-examples">Summary Examples</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#type-parameter-declarations">Type Parameter Declarations</a></li>
<li><a class="reference internal" href="#upper-bound-specification">Upper Bound Specification</a></li>
<li><a class="reference internal" href="#constrained-type-specification">Constrained Type Specification</a></li>
<li><a class="reference internal" href="#runtime-representation-of-bounds-and-constraints">Runtime Representation of Bounds and Constraints</a></li>
<li><a class="reference internal" href="#generic-type-alias">Generic Type Alias</a></li>
<li><a class="reference internal" href="#runtime-type-alias-class">Runtime Type Alias Class</a></li>
<li><a class="reference internal" href="#type-parameter-scopes">Type Parameter Scopes</a></li>
<li><a class="reference internal" href="#accessing-type-parameters-at-runtime">Accessing Type Parameters at Runtime</a></li>
<li><a class="reference internal" href="#variance-inference">Variance Inference</a></li>
<li><a class="reference internal" href="#auto-variance-for-typevar">Auto Variance For TypeVar</a></li>
<li><a class="reference internal" href="#compatibility-with-traditional-typevars">Compatibility with Traditional TypeVars</a></li>
</ul>
</li>
<li><a class="reference internal" href="#runtime-implementation">Runtime Implementation</a><ul>
<li><a class="reference internal" href="#grammar-changes">Grammar Changes</a></li>
<li><a class="reference internal" href="#ast-changes">AST Changes</a></li>
<li><a class="reference internal" href="#lazy-evaluation">Lazy Evaluation</a></li>
<li><a class="reference internal" href="#scoping-behavior">Scoping Behavior</a></li>
<li><a class="reference internal" href="#library-changes">Library Changes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#prefix-clause">Prefix Clause</a></li>
<li><a class="reference internal" href="#angle-brackets">Angle Brackets</a></li>
<li><a class="reference internal" href="#bounds-syntax">Bounds Syntax</a></li>
<li><a class="reference internal" href="#explicit-variance">Explicit Variance</a></li>
<li><a class="reference internal" href="#name-mangling">Name Mangling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-survey-of-type-parameter-syntax">Appendix A: Survey of Type Parameter Syntax</a><ul>
<li><a class="reference internal" href="#c">C++</a></li>
<li><a class="reference internal" href="#java">Java</a></li>
<li><a class="reference internal" href="#id2">C#</a></li>
<li><a class="reference internal" href="#typescript">TypeScript</a></li>
<li><a class="reference internal" href="#scala">Scala</a></li>
<li><a class="reference internal" href="#swift">Swift</a></li>
<li><a class="reference internal" href="#rust">Rust</a></li>
<li><a class="reference internal" href="#kotlin">Kotlin</a></li>
<li><a class="reference internal" href="#julia">Julia</a></li>
<li><a class="reference internal" href="#dart">Dart</a></li>
<li><a class="reference internal" href="#go">Go</a></li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="pep-banner canonical-typing-spec sticky-banner admonition attention">
<p class="admonition-title">Attention</p>
<p>This PEP is a historical document: see <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/generics.html#variance-inference" title="(in typing)"><span>Variance Inference</span></a>,
<a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/aliases.html#type-aliases" title="(in typing)"><span>Type aliases</span></a>,
<a class="reference external" href="https://docs.python.org/3/reference/compound_stmts.html#type-params" title="(in Python v3.13)"><span>Type parameter lists</span></a>,
<a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#type" title="(in Python v3.13)"><span>The type statement</span></a> and
<a class="reference external" href="https://docs.python.org/3/reference/executionmodel.html#annotation-scopes" title="(in Python v3.13)"><span>Annotation scopes</span></a>. for up-to-date specs and documentation. Canonical typing specs are maintained at the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>; runtime typing behaviour is described in the CPython documentation.</p>
<p class="close-button">×</p>
<p>See the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/meta.html">typing specification update process</a> for how to propose changes to the typing spec.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP specifies an improved syntax for specifying type parameters within
a generic class, function, or type alias. It also introduces a new statement
for declaring type aliases.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> introduced type variables into the language. <a class="pep reference internal" href="../pep-0612/" title="PEP 612 Parameter Specification Variables">PEP 612</a> built
upon this concept by introducing parameter specifications, and
<a class="pep reference internal" href="../pep-0646/" title="PEP 646 Variadic Generics">PEP 646</a> added variadic type variables.</p>
<p>While generic types and type parameters have grown in popularity, the
syntax for specifying type parameters still feels “bolted on” to Python.
This is a source of confusion among Python developers.</p>
<p>There is consensus within the Python static typing community that it is time
to provide a formal syntax that is similar to other modern programming
languages that support generic types.</p>
<p>An analysis of 25 popular typed Python libraries revealed that type
variables (in particular, the <code class="docutils literal notranslate"><span class="pre">typing.TypeVar</span></code> symbol) were used in
14% of modules.</p>
<section id="points-of-confusion">
<h3><a class="toc-backref" href="#points-of-confusion" role="doc-backlink">Points of Confusion</a></h3>
<p>While the use of type variables has become widespread, the manner in which
they are specified within code is the source of confusion among many
Python developers. There are a couple of factors that contribute to this
confusion.</p>
<p>The scoping rules for type variables are difficult to understand. Type
variables are typically allocated within the global scope, but their semantic
meaning is valid only when used within the context of a generic class,
function, or type alias. A single runtime instance of a type variable may be
reused in multiple generic contexts, and it has a different semantic meaning
in each of these contexts. This PEP proposes to eliminate this source of
confusion by declaring type parameters at a natural place within a class,
function, or type alias declaration statement.</p>
<p>Generic type aliases are often misused because it is not clear to developers
that a type argument must be supplied when the type alias is used. This leads
to an implied type argument of <code class="docutils literal notranslate"><span class="pre">Any</span></code>, which is rarely the intent. This PEP
proposes to add new syntax that makes generic type alias declarations
clear.</p>
<p><a class="pep reference internal" href="../pep-0483/" title="PEP 483 The Theory of Type Hints">PEP 483</a> and <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> introduced the concept of “variance” for a type
variable used within a generic class. Type variables can be invariant,
covariant, or contravariant. The concept of variance is an advanced detail
of type theory that is not well understood by most Python developers, yet
they must confront this concept today when defining their first generic
class. This PEP largely eliminates the need for most developers
to understand the concept of variance when defining generic classes.</p>
<p>When more than one type parameter is used with a generic class or type alias,
the rules for type parameter ordering can be confusing. It is normally based on
the order in which they first appear within a class or type alias declaration
statement. However, this can be overridden in a class definition by
including a “Generic” or “Protocol” base class. For example, in the class
declaration <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">ClassA(Mapping[K,</span> <span class="pre">V])</span></code>, the type parameters are
ordered as <code class="docutils literal notranslate"><span class="pre">K</span></code> and then <code class="docutils literal notranslate"><span class="pre">V</span></code>. However, in the class declaration
<code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">ClassB(Mapping[K,</span> <span class="pre">V],</span> <span class="pre">Generic[V,</span> <span class="pre">K])</span></code>, the type parameters are
ordered as <code class="docutils literal notranslate"><span class="pre">V</span></code> and then <code class="docutils literal notranslate"><span class="pre">K</span></code>. This PEP proposes to make type parameter
ordering explicit in all cases.</p>
<p>The practice of sharing a type variable across multiple generic contexts
creates other problems today. Modern editors provide features like “find
all references” and “rename all references” that operate on symbols at the
semantic level. When a type parameter is shared among multiple generic
classes, functions, and type aliases, all references are semantically
equivalent.</p>
<p>Type variables defined within the global scope also need to be given a name
that starts with an underscore to indicate that the variable is private to
the module. Globally-defined type variables are also often given names to
indicate their variance, leading to cumbersome names like “_T_contra” and
“_KT_co”. The current mechanisms for allocating type variables also requires
the developer to supply a redundant name in quotes (e.g. <code class="docutils literal notranslate"><span class="pre">T</span> <span class="pre">=</span> <span class="pre">TypeVar(&quot;T&quot;)</span></code>).
This PEP eliminates the need for the redundant name and cumbersome
variable names.</p>
<p>Defining type parameters today requires importing the <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> and
<code class="docutils literal notranslate"><span class="pre">Generic</span></code> symbols from the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module. Over the past several releases
of Python, efforts have been made to eliminate the need to import <code class="docutils literal notranslate"><span class="pre">typing</span></code>
symbols for common use cases, and the PEP furthers this goal.</p>
</section>
</section>
<section id="summary-examples">
<h2><a class="toc-backref" href="#summary-examples" role="doc-backlink">Summary Examples</a></h2>
<p>Defining a generic class prior to this PEP looks something like this.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
<span class="n">_T_co</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;_T_co&quot;</span><span class="p">,</span> <span class="n">covariant</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">_T_co</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">_T_co</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>With the new syntax, it looks like this.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">str</span><span class="p">]:</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Here is an example of a generic function today.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeVar</span>
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;_T&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">_T</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">_T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">_T</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>And the new syntax.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">func</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">a</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Here is an example of a generic type alias today.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeAlias</span>
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;_T&quot;</span><span class="p">)</span>
<span class="n">ListOrSet</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">_T</span><span class="p">]</span> <span class="o">|</span> <span class="nb">set</span><span class="p">[</span><span class="n">_T</span><span class="p">]</span>
</pre></div>
</div>
<p>And with the new syntax.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span> <span class="n">ListOrSet</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="nb">set</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
</pre></div>
</div>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<section id="type-parameter-declarations">
<h3><a class="toc-backref" href="#type-parameter-declarations" role="doc-backlink">Type Parameter Declarations</a></h3>
<p>Here is a new syntax for declaring type parameters for generic
classes, functions, and type aliases. The syntax adds support for
a comma-delimited list of type parameters in square brackets after
the name of the class, function, or type alias.</p>
<p>Simple (non-variadic) type variables are declared with an unadorned name.
Variadic type variables are preceded by <code class="docutils literal notranslate"><span class="pre">*</span></code> (see <a class="pep reference internal" href="../pep-0646/" title="PEP 646 Variadic Generics">PEP 646</a> for details).
Parameter specifications are preceded by <code class="docutils literal notranslate"><span class="pre">**</span></code> (see <a class="pep reference internal" href="../pep-0612/" title="PEP 612 Parameter Specification Variables">PEP 612</a> for details).</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This generic class is parameterized by a TypeVar T, a</span>
<span class="c1"># TypeVarTuple Ts, and a ParamSpec P.</span>
<span class="k">class</span> <span class="nc">ChildClass</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="o">*</span><span class="n">Ts</span><span class="p">,</span> <span class="o">**</span><span class="n">P</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>There is no need to include <code class="docutils literal notranslate"><span class="pre">Generic</span></code> as a base class. Its inclusion as
a base class is implied by the presence of type parameters, and it will
automatically be included in the <code class="docutils literal notranslate"><span class="pre">__mro__</span></code> and <code class="docutils literal notranslate"><span class="pre">__orig_bases__</span></code> attributes
for the class. The explicit use of a <code class="docutils literal notranslate"><span class="pre">Generic</span></code> base class will result in a
runtime error.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Runtime error</span>
</pre></div>
</div>
<p>A <code class="docutils literal notranslate"><span class="pre">Protocol</span></code> base class with type arguments may generate a runtime
error. Type checkers should generate an error in this case because
the use of type arguments is not needed, and the order of type parameters
for the class are no longer dictated by their order in the <code class="docutils literal notranslate"><span class="pre">Protocol</span></code>
base class.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">](</span><span class="n">Protocol</span><span class="p">):</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassB</span><span class="p">[</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">](</span><span class="n">Protocol</span><span class="p">[</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Recommended type checker error</span>
</pre></div>
</div>
<p>Type parameter names within a generic class, function, or type alias must be
unique within that same class, function, or type alias. A duplicate name
generates a syntax error at compile time. This is consistent with the
requirement that parameter names within a function signature must be unique.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="o">*</span><span class="n">T</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># Syntax Error</span>
<span class="k">def</span> <span class="nf">func1</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="o">**</span><span class="n">T</span><span class="p">]():</span> <span class="o">...</span> <span class="c1"># Syntax Error</span>
</pre></div>
</div>
<p>Class type parameter names are mangled if they begin with a double
underscore, to avoid complicating the name lookup mechanism for names used
within the class. However, the <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute of the type parameter
will hold the non-mangled name.</p>
</section>
<section id="upper-bound-specification">
<h3><a class="toc-backref" href="#upper-bound-specification" role="doc-backlink">Upper Bound Specification</a></h3>
<p>For a non-variadic type parameter, an “upper bound” type can be specified
through the use of a type annotation expression. If an upper bound is
not specified, the upper bound is assumed to be <code class="docutils literal notranslate"><span class="pre">object</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">str</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>The specified upper bound type must use an expression form that is allowed in
type annotations. More complex expression forms should be flagged
as an error by a type checker. Quoted forward references are allowed.</p>
<p>The specified upper bound type must be concrete. An attempt to use a generic
type should be flagged as an error by a type checker. This is consistent with
the existing rules enforced by type checkers for a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> constructor call.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]:</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassB</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="s2">&quot;ForwardReference&quot;</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassC</span><span class="p">[</span><span class="n">V</span><span class="p">]:</span>
<span class="k">class</span> <span class="nc">ClassD</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">V</span><span class="p">]]:</span> <span class="o">...</span> <span class="c1"># Type checker error: generic type</span>
<span class="k">class</span> <span class="nc">ClassE</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]:</span> <span class="o">...</span> <span class="c1"># Type checker error: illegal expression form</span>
</pre></div>
</div>
</section>
<section id="constrained-type-specification">
<h3><a class="toc-backref" href="#constrained-type-specification" role="doc-backlink">Constrained Type Specification</a></h3>
<p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> introduced the concept of a “constrained type variable” which is
constrained to a set of two or more types. The new syntax supports this type
of constraint through the use of a literal tuple expression that contains
two or more types.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">AnyStr</span><span class="p">:</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">)]:</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassB</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;ForwardReference&quot;</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">)]:</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassC</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">()]:</span> <span class="o">...</span> <span class="c1"># Type checker error: two or more types required</span>
<span class="k">class</span> <span class="nc">ClassD</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="p">)]:</span> <span class="o">...</span> <span class="c1"># Type checker error: two or more types required</span>
<span class="n">t1</span> <span class="o">=</span> <span class="p">(</span><span class="nb">bytes</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ClassE</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="n">t1</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># Type checker error: literal tuple expression required</span>
</pre></div>
</div>
<p>If the specified type is not a tuple expression or the tuple expression includes
complex expression forms that are not allowed in a type annotation, a type
checker should generate an error. Quoted forward references are allowed.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassF</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">)]:</span> <span class="o">...</span> <span class="c1"># Type checker error: invalid expression form</span>
</pre></div>
</div>
<p>The specified constrained types must be concrete. An attempt to use a generic
type should be flagged as an error by a type checker. This is consistent with
the existing rules enforced by type checkers for a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> constructor call.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassG</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="p">(</span><span class="nb">list</span><span class="p">[</span><span class="n">S</span><span class="p">],</span> <span class="nb">str</span><span class="p">)]:</span> <span class="o">...</span> <span class="c1"># Type checker error: generic type</span>
</pre></div>
</div>
</section>
<section id="runtime-representation-of-bounds-and-constraints">
<h3><a class="toc-backref" href="#runtime-representation-of-bounds-and-constraints" role="doc-backlink">Runtime Representation of Bounds and Constraints</a></h3>
<p>The upper bounds and constraints of <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> objects are accessible at
runtime through the <code class="docutils literal notranslate"><span class="pre">__bound__</span></code> and <code class="docutils literal notranslate"><span class="pre">__constraints__</span></code> attributes.
For <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> objects defined through the new syntax, these attributes
become lazily evaluated, as discussed under <a class="reference internal" href="#lazy-evaluation">Lazy Evaluation</a> below.</p>
</section>
<section id="generic-type-alias">
<h3><a class="toc-backref" href="#generic-type-alias" role="doc-backlink">Generic Type Alias</a></h3>
<p>We propose to introduce a new statement for declaring type aliases. Similar
to <code class="docutils literal notranslate"><span class="pre">class</span></code> and <code class="docutils literal notranslate"><span class="pre">def</span></code> statements, a <code class="docutils literal notranslate"><span class="pre">type</span></code> statement defines a scope
for type parameters.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># A non-generic type alias</span>
<span class="nb">type</span> <span class="n">IntOrStr</span> <span class="o">=</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span>
<span class="c1"># A generic type alias</span>
<span class="nb">type</span> <span class="n">ListOrSet</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="nb">set</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
</pre></div>
</div>
<p>Type aliases can refer to themselves without the use of quotes.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># A type alias that includes a forward reference</span>
<span class="nb">type</span> <span class="n">AnimalOrVegetable</span> <span class="o">=</span> <span class="n">Animal</span> <span class="o">|</span> <span class="s2">&quot;Vegetable&quot;</span>
<span class="c1"># A generic self-referential type alias</span>
<span class="nb">type</span> <span class="n">RecursiveList</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="n">T</span> <span class="o">|</span> <span class="nb">list</span><span class="p">[</span><span class="n">RecursiveList</span><span class="p">[</span><span class="n">T</span><span class="p">]]</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">type</span></code> keyword is a new soft keyword. It is interpreted as a keyword
only in this part of the grammar. In all other locations, it is assumed to
be an identifier name.</p>
<p>Type parameters declared as part of a generic type alias are valid only
when evaluating the right-hand side of the type alias.</p>
<p>As with <code class="docutils literal notranslate"><span class="pre">typing.TypeAlias</span></code>, type checkers should restrict the right-hand
expression to expression forms that are allowed within type annotations.
The use of more complex expression forms (call expressions, ternary operators,
arithmetic operators, comparison operators, etc.) should be flagged as an
error.</p>
<p>Type alias expressions are not allowed to use traditional type variables (i.e.
those allocated with an explicit <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> constructor call). Type checkers
should generate an error in this case.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T&quot;</span><span class="p">)</span>
<span class="nb">type</span> <span class="n">MyList</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="c1"># Type checker error: traditional type variable usage</span>
</pre></div>
</div>
<p>We propose to deprecate the existing <code class="docutils literal notranslate"><span class="pre">typing.TypeAlias</span></code> introduced in
<a class="pep reference internal" href="../pep-0613/" title="PEP 613 Explicit Type Aliases">PEP 613</a>. The new syntax eliminates its need entirely.</p>
</section>
<section id="runtime-type-alias-class">
<h3><a class="toc-backref" href="#runtime-type-alias-class" role="doc-backlink">Runtime Type Alias Class</a></h3>
<p>At runtime, a <code class="docutils literal notranslate"><span class="pre">type</span></code> statement will generate an instance of
<code class="docutils literal notranslate"><span class="pre">typing.TypeAliasType</span></code>. This class represents the type. Its attributes
include:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">__name__</span></code> is a str representing the name of the type alias</li>
<li><code class="docutils literal notranslate"><span class="pre">__type_params__</span></code> is a tuple of <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>, or
<code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> objects that parameterize the type alias if it is generic</li>
<li><code class="docutils literal notranslate"><span class="pre">__value__</span></code> is the evaluated value of the type alias</li>
</ul>
<p>All of these attributes are read-only.</p>
<p>The value of the type alias is evaluated lazily (see <a class="reference internal" href="#lazy-evaluation">Lazy Evaluation</a> below).</p>
</section>
<section id="type-parameter-scopes">
<h3><a class="toc-backref" href="#type-parameter-scopes" role="doc-backlink">Type Parameter Scopes</a></h3>
<p>When the new syntax is used, a new lexical scope is introduced, and this scope
includes the type parameters. Type parameters can be accessed by name
within inner scopes. As with other symbols in Python, an inner scope can
define its own symbol that overrides an outer-scope symbol of the same name.
This section provides a verbal description of the new scoping rules.
The <a class="reference internal" href="#id1">Scoping Behavior</a> section below specifies the behavior in terms
of a translation to near-equivalent existing Python code.</p>
<p>Type parameters are visible to other
type parameters declared elsewhere in the list. This allows type parameters
to use other type parameters within their definition. While there is currently
no use for this capability, it preserves the ability in the future to support
upper bound expressions or type argument defaults that depend on earlier
type parameters.</p>
<p>A compiler error or runtime exception is generated if the definition of an
earlier type parameter references a later type parameter even if the name is
defined in an outer scope.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># The following generates no compiler error, but a type checker</span>
<span class="c1"># should generate an error because an upper bound type must be concrete,</span>
<span class="c1"># and ``Sequence[S]`` is generic. Future extensions to the type system may</span>
<span class="c1"># eliminate this limitation.</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">S</span><span class="p">]]:</span> <span class="o">...</span>
<span class="c1"># The following generates no compiler error, because the bound for ``S``</span>
<span class="c1"># is lazily evaluated. However, type checkers should generate an error.</span>
<span class="k">class</span> <span class="nc">ClassB</span><span class="p">[</span><span class="n">S</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">T</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>A type parameter declared as part of a generic class is valid within the
class body and inner scopes contained therein. Type parameters are also
accessible when evaluating the argument list (base classes and any keyword
arguments) that comprise the class definition. This allows base classes
to be parameterized by these type parameters. Type parameters are not
accessible outside of the class body, including class decorators.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">BaseClass</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">param</span> <span class="o">=</span> <span class="n">Foo</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Runtime error: &#39;T&#39; is not defined</span>
<span class="nd">@dec</span><span class="p">(</span><span class="n">Foo</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="c1"># Runtime error: &#39;T&#39; is not defined</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>A type parameter declared as part of a generic function is valid within
the function body and any scopes contained therein. It is also valid within
parameter and return type annotations. Default argument values for function
parameters are evaluated outside of this scope, so type parameters are
not accessible in default value expressions. Likewise, type parameters are not
in scope for function decorators.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">func1</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">a</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Runtime error: &#39;T&#39; is not defined</span>
<span class="k">def</span> <span class="nf">func2</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">a</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Runtime error: &#39;T&#39; is not defined</span>
<span class="nd">@dec</span><span class="p">(</span><span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="c1"># Runtime error: &#39;T&#39; is not defined</span>
<span class="k">def</span> <span class="nf">func3</span><span class="p">[</span><span class="n">T</span><span class="p">]():</span> <span class="o">...</span>
</pre></div>
</div>
<p>A type parameter declared as part of a generic type alias is valid within
the type alias expression.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span> <span class="n">Alias1</span><span class="p">[</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">]</span> <span class="o">=</span> <span class="n">Mapping</span><span class="p">[</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">]</span> <span class="o">|</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">K</span><span class="p">]</span>
</pre></div>
</div>
<p>Type parameter symbols defined in outer scopes cannot be bound with
<code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> statements in inner scopes.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">S</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">outer1</span><span class="p">[</span><span class="n">S</span><span class="p">]():</span>
<span class="n">S</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">T</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">outer2</span><span class="p">[</span><span class="n">T</span><span class="p">]():</span>
<span class="k">def</span> <span class="nf">inner1</span><span class="p">():</span>
<span class="k">nonlocal</span> <span class="n">S</span> <span class="c1"># OK because it binds variable S from outer1</span>
<span class="k">nonlocal</span> <span class="n">T</span> <span class="c1"># Syntax error: nonlocal binding not allowed for type parameter</span>
<span class="k">def</span> <span class="nf">inner2</span><span class="p">():</span>
<span class="k">global</span> <span class="n">S</span> <span class="c1"># OK because it binds variable S from global scope</span>
</pre></div>
</div>
<p>The lexical scope introduced by the new type parameter syntax is unlike
traditional scopes introduced by a <code class="docutils literal notranslate"><span class="pre">def</span></code> or <code class="docutils literal notranslate"><span class="pre">class</span></code> statement. A type
parameter scope acts more like a temporary “overlay” to the containing scope.
The only new symbols contained
within its symbol table are the type parameters defined using the new syntax.
References to all other symbols are treated as though they were found within
the containing scope. This allows base class lists (in class definitions) and
type annotation expressions (in function definitions) to reference symbols
defined in the containing scope.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Outer</span><span class="p">:</span>
<span class="k">class</span> <span class="nc">Private</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># If the type parameter scope was like a traditional scope,</span>
<span class="c1"># the base class &#39;Private&#39; would not be accessible here.</span>
<span class="k">class</span> <span class="nc">Inner</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">Private</span><span class="p">,</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="k">pass</span>
<span class="c1"># Likewise, &#39;Inner&#39; would not be available in these type annotations.</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">Inner</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Inner</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">a</span>
</pre></div>
</div>
<p>The compiler allows inner scopes to define a local symbol that overrides an
outer-scoped type parameter.</p>
<p>Consistent with the scoping rules defined in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>, type checkers should
generate an error if inner-scoped generic classes, functions, or type aliases
reuse the same type parameter name as an outer scope.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@decorator</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Argument expression `T` evaluates to 0</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="n">T</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># All methods below should result in a type checker error</span>
<span class="c1"># &quot;type parameter &#39;T&#39; already in use&quot; because they are using the</span>
<span class="c1"># type parameter &#39;T&#39;, which is already in use by the outer scope</span>
<span class="c1"># &#39;ClassA&#39;.</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method2</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span> <span class="o">=</span> <span class="n">T</span><span class="p">):</span> <span class="c1"># Parameter &#39;x&#39; gets default value of 1</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method3</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">):</span> <span class="c1"># Parameter &#39;x&#39; has type T (scoped to method3)</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Symbols referenced in inner scopes are resolved using existing rules except
that type parameter scopes are also considered during name resolution.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># T refers to the global variable</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 0</span>
<span class="k">class</span> <span class="nc">Outer</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="n">T</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># T refers to the local variable scoped to class &#39;Outer&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 1</span>
<span class="k">class</span> <span class="nc">Inner1</span><span class="p">:</span>
<span class="n">T</span> <span class="o">=</span> <span class="mi">2</span>
<span class="c1"># T refers to the local type variable within &#39;Inner1&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 2</span>
<span class="k">def</span> <span class="nf">inner_method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># T refers to the type parameter scoped to class &#39;Outer&#39;;</span>
<span class="c1"># If &#39;Outer&#39; did not use the new type parameter syntax,</span>
<span class="c1"># this would instead refer to the global variable &#39;T&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints &#39;T&#39;</span>
<span class="k">def</span> <span class="nf">outer_method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">T</span> <span class="o">=</span> <span class="mi">3</span>
<span class="c1"># T refers to the local variable within &#39;outer_method&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 3</span>
<span class="k">def</span> <span class="nf">inner_func</span><span class="p">():</span>
<span class="c1"># T refers to the variable captured from &#39;outer_method&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 3</span>
</pre></div>
</div>
<p>When the new type parameter syntax is used for a generic class, assignment
expressions are not allowed within the argument list for the class definition.
Likewise, with functions that use the new type parameter syntax, assignment
expressions are not allowed within parameter or return type annotations, nor
are they allowed within the expression that defines a type alias, or within
the bounds and constraints of a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>. Similarly, <code class="docutils literal notranslate"><span class="pre">yield</span></code>, <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code>,
and <code class="docutils literal notranslate"><span class="pre">await</span></code> expressions are disallowed in these contexts.</p>
<p>This restriction is necessary because expressions evaluated within the
new lexical scope should not introduce symbols within that scope other than
the defined type parameters, and should not affect whether the enclosing function
is a generator or coroutine.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T</span><span class="p">]((</span><span class="n">x</span> <span class="o">:=</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">])):</span> <span class="o">...</span> <span class="c1"># Syntax error: assignment expression not allowed</span>
<span class="k">def</span> <span class="nf">func1</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">val</span><span class="p">:</span> <span class="p">(</span><span class="n">x</span> <span class="o">:=</span> <span class="nb">int</span><span class="p">)):</span> <span class="o">...</span> <span class="c1"># Syntax error: assignment expression not allowed</span>
<span class="k">def</span> <span class="nf">func2</span><span class="p">[</span><span class="n">T</span><span class="p">]()</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">x</span> <span class="o">:=</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Syntax error: assignment expression not allowed</span>
<span class="nb">type</span> <span class="n">Alias1</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">:=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="c1"># Syntax error: assignment expression not allowed</span>
</pre></div>
</div>
</section>
<section id="accessing-type-parameters-at-runtime">
<h3><a class="toc-backref" href="#accessing-type-parameters-at-runtime" role="doc-backlink">Accessing Type Parameters at Runtime</a></h3>
<p>A new attribute called <code class="docutils literal notranslate"><span class="pre">__type_params__</span></code> is available on generic classes,
functions, and type aliases. This attribute is a tuple of the
type parameters that parameterize the class, function, or alias.
The tuple contains <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code>, and <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> instances.</p>
<p>Type parameters declared using the new syntax will not appear within the
dictionary returned by <code class="docutils literal notranslate"><span class="pre">globals()</span></code> or <code class="docutils literal notranslate"><span class="pre">locals()</span></code>.</p>
</section>
<section id="variance-inference">
<h3><a class="toc-backref" href="#variance-inference" role="doc-backlink">Variance Inference</a></h3>
<p>This PEP eliminates the need for variance to be specified for type
parameters. Instead, type checkers will infer the variance of type parameters
based on their usage within a class. Type parameters are inferred to be
invariant, covariant, or contravariant depending on how they are used.</p>
<p>Python type checkers already include the ability to determine the variance of
type parameters for the purpose of validating variance within a generic
protocol class. This capability can be used for all classes (whether or not
they are protocols) to calculate the variance of each type parameter.</p>
<p>The algorithm for computing the variance of a type parameter is as follows.</p>
<p>For each type parameter in a generic class:</p>
<p>1. If the type parameter is variadic (<code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>) or a parameter
specification (<code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code>), it is always considered invariant. No further
inference is needed.</p>
<p>2. If the type parameter comes from a traditional <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> declaration and
is not specified as <code class="docutils literal notranslate"><span class="pre">infer_variance</span></code> (see below), its variance is specified
by the <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> constructor call. No further inference is needed.</p>
<p>3. Create two specialized versions of the class. Well refer to these as
<code class="docutils literal notranslate"><span class="pre">upper</span></code> and <code class="docutils literal notranslate"><span class="pre">lower</span></code> specializations. In both of these specializations,
replace all type parameters other than the one being inferred by a dummy type
instance (a concrete anonymous class that is type compatible with itself and
assumed to meet the bounds or constraints of the type parameter). In
the <code class="docutils literal notranslate"><span class="pre">upper</span></code> specialized class, specialize the target type parameter with
an <code class="docutils literal notranslate"><span class="pre">object</span></code> instance. This specialization ignores the type parameters
upper bound or constraints. In the <code class="docutils literal notranslate"><span class="pre">lower</span></code> specialized class, specialize
the target type parameter with itself (i.e. the corresponding type argument
is the type parameter itself).</p>
<p>4. Determine whether <code class="docutils literal notranslate"><span class="pre">lower</span></code> can be assigned to <code class="docutils literal notranslate"><span class="pre">upper</span></code> using normal type
compatibility rules. If so, the target type parameter is covariant. If not,
determine whether <code class="docutils literal notranslate"><span class="pre">upper</span></code> can be assigned to <code class="docutils literal notranslate"><span class="pre">lower</span></code>. If so, the target
type parameter is contravariant. If neither of these combinations are
assignable, the target type parameter is invariant.</p>
<p>Here is an example.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">,</span> <span class="n">T3</span><span class="p">](</span><span class="nb">list</span><span class="p">[</span><span class="n">T1</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">T2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method2</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T3</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>To determine the variance of <code class="docutils literal notranslate"><span class="pre">T1</span></code>, we specialize <code class="docutils literal notranslate"><span class="pre">ClassA</span></code> as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">upper</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="nb">object</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">]</span>
<span class="n">lower</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="n">T1</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">]</span>
</pre></div>
</div>
<p>We find that <code class="docutils literal notranslate"><span class="pre">upper</span></code> is not assignable to <code class="docutils literal notranslate"><span class="pre">lower</span></code> using normal type
compatibility rules defined in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>. Likewise, <code class="docutils literal notranslate"><span class="pre">lower</span></code> is not assignable
to <code class="docutils literal notranslate"><span class="pre">upper</span></code>, so we conclude that <code class="docutils literal notranslate"><span class="pre">T1</span></code> is invariant.</p>
<p>To determine the variance of <code class="docutils literal notranslate"><span class="pre">T2</span></code>, we specialize <code class="docutils literal notranslate"><span class="pre">ClassA</span></code> as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">upper</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="n">Dummy</span><span class="p">,</span> <span class="nb">object</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">]</span>
<span class="n">lower</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="n">Dummy</span><span class="p">,</span> <span class="n">T2</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">]</span>
</pre></div>
</div>
<p>Since <code class="docutils literal notranslate"><span class="pre">upper</span></code> is assignable to <code class="docutils literal notranslate"><span class="pre">lower</span></code>, <code class="docutils literal notranslate"><span class="pre">T2</span></code> is contravariant.</p>
<p>To determine the variance of <code class="docutils literal notranslate"><span class="pre">T3</span></code>, we specialize <code class="docutils literal notranslate"><span class="pre">ClassA</span></code> as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">upper</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="n">Dummy</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">,</span> <span class="nb">object</span><span class="p">]</span>
<span class="n">lower</span> <span class="o">=</span> <span class="n">ClassA</span><span class="p">[</span><span class="n">Dummy</span><span class="p">,</span> <span class="n">Dummy</span><span class="p">,</span> <span class="n">T3</span><span class="p">]</span>
</pre></div>
</div>
<p>Since <code class="docutils literal notranslate"><span class="pre">lower</span></code> is assignable to <code class="docutils literal notranslate"><span class="pre">upper</span></code>, <code class="docutils literal notranslate"><span class="pre">T3</span></code> is covariant.</p>
</section>
<section id="auto-variance-for-typevar">
<h3><a class="toc-backref" href="#auto-variance-for-typevar" role="doc-backlink">Auto Variance For TypeVar</a></h3>
<p>The existing <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> class constructor accepts keyword parameters named
<code class="docutils literal notranslate"><span class="pre">covariant</span></code> and <code class="docutils literal notranslate"><span class="pre">contravariant</span></code>. If both of these are <code class="docutils literal notranslate"><span class="pre">False</span></code>, the
type variable is assumed to be invariant. We propose to add another keyword
parameter named <code class="docutils literal notranslate"><span class="pre">infer_variance</span></code> indicating that a type checker should use
inference to determine whether the type variable is invariant, covariant or
contravariant. A corresponding instance variable <code class="docutils literal notranslate"><span class="pre">__infer_variance__</span></code> can be
accessed at runtime to determine whether the variance is inferred. Type
variables that are implicitly allocated using the new syntax will always
have <code class="docutils literal notranslate"><span class="pre">__infer_variance__</span></code> set to <code class="docutils literal notranslate"><span class="pre">True</span></code>.</p>
<p>A generic class that uses the traditional syntax may include combinations of
type variables with explicit and inferred variance.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T1</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T1&quot;</span><span class="p">,</span> <span class="n">infer_variance</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Inferred variance</span>
<span class="n">T2</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T2&quot;</span><span class="p">)</span> <span class="c1"># Invariant</span>
<span class="n">T3</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T3&quot;</span><span class="p">,</span> <span class="n">covariant</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># Covariant</span>
<span class="c1"># A type checker should infer the variance for T1 but use the</span>
<span class="c1"># specified variance for T2 and T3.</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">,</span> <span class="n">T3</span><span class="p">]):</span> <span class="o">...</span>
</pre></div>
</div>
</section>
<section id="compatibility-with-traditional-typevars">
<h3><a class="toc-backref" href="#compatibility-with-traditional-typevars" role="doc-backlink">Compatibility with Traditional TypeVars</a></h3>
<p>The existing mechanism for allocating <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>, and
<code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> is retained for backward compatibility. However, these
“traditional” type variables should not be combined with type parameters
allocated using the new syntax. Such a combination should be flagged as
an error by type checkers. This is necessary because the type parameter
order is ambiguous.</p>
<p>It is OK to combine traditional type variables with new-style type parameters
if the class, function, or type alias does not use the new syntax. The
new-style type parameters must come from an outer scope in this case.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">K</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;K&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">[</span><span class="n">V</span><span class="p">](</span><span class="nb">dict</span><span class="p">[</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Type checker error</span>
<span class="k">class</span> <span class="nc">ClassB</span><span class="p">[</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">](</span><span class="nb">dict</span><span class="p">[</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">ClassC</span><span class="p">[</span><span class="n">V</span><span class="p">]:</span>
<span class="c1"># The use of K and V for &quot;method1&quot; is OK because it uses the</span>
<span class="c1"># &quot;traditional&quot; generic function mechanism where type parameters</span>
<span class="c1"># are implicit. In this case V comes from an outer scope (ClassC)</span>
<span class="c1"># and K is introduced implicitly as a type parameter for &quot;method1&quot;.</span>
<span class="k">def</span> <span class="nf">method1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">V</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">K</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">V</span> <span class="o">|</span> <span class="n">K</span><span class="p">:</span> <span class="o">...</span>
<span class="c1"># The use of M and K are not allowed for &quot;method2&quot;. A type checker</span>
<span class="c1"># should generate an error in this case because this method uses the</span>
<span class="c1"># new syntax for type parameters, and all type parameters associated</span>
<span class="c1"># with the method must be explicitly declared. In this case, ``K``</span>
<span class="c1"># is not declared by &quot;method2&quot;, nor is it supplied by a new-style</span>
<span class="c1"># type parameter defined in an outer scope.</span>
<span class="k">def</span> <span class="nf">method2</span><span class="p">[</span><span class="n">M</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">M</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">K</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">M</span> <span class="o">|</span> <span class="n">K</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
</section>
</section>
<section id="runtime-implementation">
<h2><a class="toc-backref" href="#runtime-implementation" role="doc-backlink">Runtime Implementation</a></h2>
<section id="grammar-changes">
<h3><a class="toc-backref" href="#grammar-changes" role="doc-backlink">Grammar Changes</a></h3>
<p>This PEP introduces a new soft keyword <code class="docutils literal notranslate"><span class="pre">type</span></code>. It modifies the grammar
in the following ways:</p>
<ol class="arabic simple">
<li>Addition of optional type parameter clause in <code class="docutils literal notranslate"><span class="pre">class</span></code> and <code class="docutils literal notranslate"><span class="pre">def</span></code> statements.</li>
</ol>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">type_params</span><span class="p">:</span> <span class="s1">&#39;[&#39;</span> <span class="n">t</span><span class="o">=</span><span class="n">type_param_seq</span> <span class="s1">&#39;]&#39;</span>
<span class="n">type_param_seq</span><span class="p">:</span> <span class="n">a</span><span class="p">[</span><span class="n">asdl_typeparam_seq</span><span class="o">*</span><span class="p">]</span><span class="o">=</span><span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">type_param</span><span class="o">+</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]</span>
<span class="n">type_param</span><span class="p">:</span>
<span class="o">|</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span> <span class="n">b</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_bound</span><span class="p">]</span>
<span class="o">|</span> <span class="s1">&#39;*&#39;</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span>
<span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span>
<span class="n">type_param_bound</span><span class="p">:</span> <span class="s2">&quot;:&quot;</span> <span class="n">e</span><span class="o">=</span><span class="n">expression</span>
<span class="c1"># Grammar definitions for class_def_raw and function_def_raw are modified</span>
<span class="c1"># to reference type_params as an optional syntax element. The definitions</span>
<span class="c1"># of class_def_raw and function_def_raw are simplified here for brevity.</span>
<span class="n">class_def_raw</span><span class="p">:</span> <span class="s1">&#39;class&#39;</span> <span class="n">n</span><span class="o">=</span><span class="n">NAME</span> <span class="n">t</span><span class="o">=</span><span class="p">[</span><span class="n">type_params</span><span class="p">]</span> <span class="o">...</span>
<span class="n">function_def_raw</span><span class="p">:</span> <span class="n">a</span><span class="o">=</span><span class="p">[</span><span class="n">ASYNC</span><span class="p">]</span> <span class="s1">&#39;def&#39;</span> <span class="n">n</span><span class="o">=</span><span class="n">NAME</span> <span class="n">t</span><span class="o">=</span><span class="p">[</span><span class="n">type_params</span><span class="p">]</span> <span class="o">...</span>
</pre></div>
</div>
<ol class="arabic simple" start="2">
<li>Addition of new <code class="docutils literal notranslate"><span class="pre">type</span></code> statement for defining type aliases.</li>
</ol>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">type_alias</span><span class="p">:</span> <span class="s2">&quot;type&quot;</span> <span class="n">n</span><span class="o">=</span><span class="n">NAME</span> <span class="n">t</span><span class="o">=</span><span class="p">[</span><span class="n">type_params</span><span class="p">]</span> <span class="s1">&#39;=&#39;</span> <span class="n">b</span><span class="o">=</span><span class="n">expression</span>
</pre></div>
</div>
</section>
<section id="ast-changes">
<h3><a class="toc-backref" href="#ast-changes" role="doc-backlink">AST Changes</a></h3>
<p>This PEP introduces a new AST node type called <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TypeAlias</span><span class="p">(</span><span class="n">expr</span> <span class="n">name</span><span class="p">,</span> <span class="n">typeparam</span><span class="o">*</span> <span class="n">typeparams</span><span class="p">,</span> <span class="n">expr</span> <span class="n">value</span><span class="p">)</span>
</pre></div>
</div>
<p>It also adds an AST node type that represents a type parameter.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>typeparam = TypeVar(identifier name, expr? bound)
| ParamSpec(identifier name)
| TypeVarTuple(identifier name)
</pre></div>
</div>
<p>Bounds and constraints are represented identically in the AST. In the implementation,
any expression that is a <code class="docutils literal notranslate"><span class="pre">Tuple</span></code> AST node is treated as a constraint, and any other
expression is treated as a bound.</p>
<p>It also modifies existing AST node types <code class="docutils literal notranslate"><span class="pre">FunctionDef</span></code>, <code class="docutils literal notranslate"><span class="pre">AsyncFunctionDef</span></code>
and <code class="docutils literal notranslate"><span class="pre">ClassDef</span></code> to include an additional optional attribute called
<code class="docutils literal notranslate"><span class="pre">typeparams</span></code> that includes a list of type parameters associated with the
function or class.</p>
</section>
<section id="lazy-evaluation">
<h3><a class="toc-backref" href="#lazy-evaluation" role="doc-backlink">Lazy Evaluation</a></h3>
<p>This PEP introduces three new contexts where expressions may occur that represent
static types: <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> bounds, <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> constraints, and the value of type
aliases. These expressions may contain references to names
that are not yet defined. For example, type aliases may be recursive, or even mutually
recursive, and type variable bounds may refer back to the current class. If these
expressions were evaluated eagerly, users would need to enclose such expressions in
quotes to prevent runtime errors. <a class="pep reference internal" href="../pep-0563/" title="PEP 563 Postponed Evaluation of Annotations">PEP 563</a> and <a class="pep reference internal" href="../pep-0649/" title="PEP 649 Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> detail the problems with
this situation for type annotations.</p>
<p>To prevent a similar situation with the new syntax proposed in this PEP, we propose
to use lazy evaluation for these expressions, similar to the approach in <a class="pep reference internal" href="../pep-0649/" title="PEP 649 Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>.
Specifically, each expression will be saved in a code object, and the code object
is evaluated only when the corresponding attribute is accessed (<code class="docutils literal notranslate"><span class="pre">TypeVar.__bound__</span></code>,
<code class="docutils literal notranslate"><span class="pre">TypeVar.__constraints__</span></code>, or <code class="docutils literal notranslate"><span class="pre">TypeAlias.__value__</span></code>). After the value is
successfully evaluated, the value is saved and later calls will return the same value
without re-evaluating the code object.</p>
<p>If <a class="pep reference internal" href="../pep-0649/" title="PEP 649 Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> is implemented, additional evaluation mechanisms should be added to
mirror the options that PEP provides for annotations. In the current version of the
PEP, that might include adding an <code class="docutils literal notranslate"><span class="pre">__evaluate_bound__</span></code> method to <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> taking
a <code class="docutils literal notranslate"><span class="pre">format</span></code> parameter with the same meaning as in PEP 649s <code class="docutils literal notranslate"><span class="pre">__annotate__</span></code> method
(and a similar <code class="docutils literal notranslate"><span class="pre">__evaluate_constraints__</span></code> method, as well as an <code class="docutils literal notranslate"><span class="pre">__evaluate_value__</span></code>
method on <code class="docutils literal notranslate"><span class="pre">TypeAliasType</span></code>).
However, until PEP 649 is accepted and implemented, only the default evaluation format
(PEP 649s “VALUE” format) will be supported.</p>
<p>As a consequence of lazy evaluation, the value observed for an attribute may
depend on the time the attribute is accessed.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">X</span> <span class="o">=</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">Foo</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="n">X</span><span class="p">,</span> <span class="n">U</span><span class="p">:</span> <span class="n">X</span><span class="p">]:</span>
<span class="n">t</span><span class="p">,</span> <span class="n">u</span> <span class="o">=</span> <span class="n">T</span><span class="p">,</span> <span class="n">U</span>
<span class="nb">print</span><span class="p">(</span><span class="n">Foo</span><span class="o">.</span><span class="n">t</span><span class="o">.</span><span class="n">__bound__</span><span class="p">)</span> <span class="c1"># prints &quot;int&quot;</span>
<span class="n">X</span> <span class="o">=</span> <span class="nb">str</span>
<span class="nb">print</span><span class="p">(</span><span class="n">Foo</span><span class="o">.</span><span class="n">u</span><span class="o">.</span><span class="n">__bound__</span><span class="p">)</span> <span class="c1"># prints &quot;str&quot;</span>
</pre></div>
</div>
<p>Similar examples affecting type annotations can be constructed using the
semantics of PEP 563 or PEP 649.</p>
<p>A naive implementation of lazy evaluation would handle class namespaces
incorrectly, because functions within a class do not normally have access to
the enclosing class namespace. The implementation will retain a reference to
the class namespace so that class-scoped names are resolved correctly.</p>
</section>
<section id="scoping-behavior">
<span id="id1"></span><h3><a class="toc-backref" href="#scoping-behavior" role="doc-backlink">Scoping Behavior</a></h3>
<p>The new syntax requires a new kind of scope that behaves differently
from existing scopes in Python. Thus, the new syntax cannot be described exactly in terms of
existing Python scoping behavior. This section specifies these scopes
further by reference to existing scoping behavior: the new scopes behave
like function scopes, except for a number of minor differences listed below.</p>
<p>All examples include functions introduced with the pseudo-keyword <code class="docutils literal notranslate"><span class="pre">def695</span></code>.
This keyword will not exist in the actual language; it is used to
clarify that the new scopes are for the most part like function scopes.</p>
<p><code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes differ from regular function scopes in the following ways:</p>
<ul class="simple">
<li>If a <code class="docutils literal notranslate"><span class="pre">def695</span></code> scope is immediately within a class scope, or within another
<code class="docutils literal notranslate"><span class="pre">def695</span></code> scope that is immediately within a class scope, then names defined
in that class scope can be accessed within the <code class="docutils literal notranslate"><span class="pre">def695</span></code> scope. (Regular functions,
by contrast, cannot access names defined within an enclosing class scope.)</li>
<li>The following constructs are disallowed directly within a <code class="docutils literal notranslate"><span class="pre">def695</span></code> scope, though
they may be used within other scopes nested inside a <code class="docutils literal notranslate"><span class="pre">def695</span></code> scope:<ul>
<li><code class="docutils literal notranslate"><span class="pre">yield</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">from</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">await</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">:=</span></code> (walrus operator)</li>
</ul>
</li>
<li>The qualified name (<code class="docutils literal notranslate"><span class="pre">__qualname__</span></code>) of objects (classes and functions) defined within <code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes
is as if the objects were defined within the closest enclosing scope.</li>
<li>Names bound within <code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes cannot be rebound with a <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> statement in nested scopes.</li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes are used for the evaluation of several new syntactic constructs proposed
in this PEP. Some are evaluated eagerly (when a type alias, function, or class is defined); others are
evaluated lazily (only when evaluation is specifically requested). In all cases, the scoping semantics are identical:</p>
<ul class="simple">
<li>Eagerly evaluated values:<ul>
<li>The type parameters of generic type aliases</li>
<li>The type parameters and annotations of generic functions</li>
<li>The type parameters and base class expressions of generic classes</li>
</ul>
</li>
<li>Lazily evaluated values:<ul>
<li>The value of generic type aliases</li>
<li>The bounds of type variables</li>
<li>The constraints of type variables</li>
</ul>
</li>
</ul>
<p>In the below translations, names that start with two underscores are internal to the implementation
and not visible to actual Python code. We use the following intrinsic functions, which in the real
implementation are defined directly in the interpreter:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">__make_typealias(*,</span> <span class="pre">name,</span> <span class="pre">type_params=(),</span> <span class="pre">evaluate_value)</span></code>: Creates a new <code class="docutils literal notranslate"><span class="pre">typing.TypeAlias</span></code> object with the given
name, type parameters, and lazily evaluated value. The value is not evaluated until the <code class="docutils literal notranslate"><span class="pre">__value__</span></code> attribute
is accessed.</li>
<li><code class="docutils literal notranslate"><span class="pre">__make_typevar_with_bound(*,</span> <span class="pre">name,</span> <span class="pre">evaluate_bound)</span></code>: Creates a new <code class="docutils literal notranslate"><span class="pre">typing.TypeVar</span></code> object with the given
name and lazily evaluated bound. The bound is not evaluated until the <code class="docutils literal notranslate"><span class="pre">__bound__</span></code> attribute is accessed.</li>
<li><code class="docutils literal notranslate"><span class="pre">__make_typevar_with_constraints(*,</span> <span class="pre">name,</span> <span class="pre">evaluate_constraints)</span></code>: Creates a new <code class="docutils literal notranslate"><span class="pre">typing.TypeVar</span></code> object with the given
name and lazily evaluated constraints. The constraints are not evaluated until the <code class="docutils literal notranslate"><span class="pre">__constraints__</span></code> attribute
is accessed.</li>
</ul>
<p>Non-generic type aliases are translated as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span> <span class="n">Alias</span> <span class="o">=</span> <span class="nb">int</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">def695</span> <span class="n">__evaluate_Alias</span><span class="p">():</span>
<span class="k">return</span> <span class="nb">int</span>
<span class="n">Alias</span> <span class="o">=</span> <span class="n">__make_typealias</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Alias&#39;</span><span class="p">,</span> <span class="n">evaluate_value</span><span class="o">=</span><span class="n">__evaluate_Alias</span><span class="p">)</span>
</pre></div>
</div>
<p>Generic type aliases:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span> <span class="n">Alias</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">def695</span> <span class="n">__generic_parameters_of_Alias</span><span class="p">():</span>
<span class="n">def695</span> <span class="n">__evaluate_T_bound</span><span class="p">():</span>
<span class="k">return</span> <span class="nb">int</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">__make_typevar_with_bound</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;T&#39;</span><span class="p">,</span> <span class="n">evaluate_bound</span><span class="o">=</span><span class="n">__evaluate_T_bound</span><span class="p">)</span>
<span class="n">def695</span> <span class="n">__evaluate_Alias</span><span class="p">():</span>
<span class="k">return</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
<span class="k">return</span> <span class="n">__make_typealias</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Alias&#39;</span><span class="p">,</span> <span class="n">type_params</span><span class="o">=</span><span class="p">(</span><span class="n">T</span><span class="p">,),</span> <span class="n">evaluate_value</span><span class="o">=</span><span class="n">__evaluate_Alias</span><span class="p">)</span>
<span class="n">Alias</span> <span class="o">=</span> <span class="n">__generic_parameters_of_Alias</span><span class="p">()</span>
</pre></div>
</div>
<p>Generic functions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">f</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">x</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">def695</span> <span class="n">__generic_parameters_of_f</span><span class="p">():</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;T&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">x</span>
<span class="n">f</span><span class="o">.</span><span class="n">__type_params__</span> <span class="o">=</span> <span class="p">(</span><span class="n">T</span><span class="p">,)</span>
<span class="k">return</span> <span class="n">f</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">__generic_parameters_of_f</span><span class="p">()</span>
</pre></div>
</div>
<p>A fuller example of generic functions, illustrating the scoping behavior of defaults, decorators, and bounds.
Note that this example does not use <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> correctly, so it should be rejected by a static type checker.
It is however valid at runtime, and it us used here to illustrate the runtime semantics.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@decorator</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">[</span><span class="n">T</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">U</span><span class="p">:</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">),</span> <span class="o">*</span><span class="n">Ts</span><span class="p">,</span> <span class="o">**</span><span class="n">P</span><span class="p">](</span>
<span class="n">x</span><span class="p">:</span> <span class="n">T</span> <span class="o">=</span> <span class="n">SOME_CONSTANT</span><span class="p">,</span>
<span class="n">y</span><span class="p">:</span> <span class="n">U</span><span class="p">,</span>
<span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="o">*</span><span class="n">Ts</span><span class="p">,</span>
<span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">P</span><span class="o">.</span><span class="n">kwargs</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">x</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">__default_of_x</span> <span class="o">=</span> <span class="n">SOME_CONSTANT</span> <span class="c1"># evaluated outside the def695 scope</span>
<span class="n">def695</span> <span class="n">__generic_parameters_of_f</span><span class="p">():</span>
<span class="n">def695</span> <span class="n">__evaluate_T_bound</span><span class="p">():</span>
<span class="k">return</span> <span class="nb">int</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">__make_typevar_with_bound</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;T&#39;</span><span class="p">,</span> <span class="n">evaluate_bound</span><span class="o">=</span><span class="n">__evaluate_T_bound</span><span class="p">)</span>
<span class="n">def695</span> <span class="n">__evaluate_U_constraints</span><span class="p">():</span>
<span class="k">return</span> <span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
<span class="n">U</span> <span class="o">=</span> <span class="n">__make_typevar_with_constraints</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;U&#39;</span><span class="p">,</span> <span class="n">evaluate_constraints</span><span class="o">=</span><span class="n">__evaluate_U_constraints</span><span class="p">)</span>
<span class="n">Ts</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVarTuple</span><span class="p">(</span><span class="s2">&quot;Ts&quot;</span><span class="p">)</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">ParamSpec</span><span class="p">(</span><span class="s2">&quot;P&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">T</span> <span class="o">=</span> <span class="n">__default_of_x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">U</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="o">*</span><span class="n">Ts</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="n">P</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">x</span>
<span class="n">f</span><span class="o">.</span><span class="n">__type_params__</span> <span class="o">=</span> <span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="p">,</span> <span class="n">Ts</span><span class="p">,</span> <span class="n">P</span><span class="p">)</span>
<span class="k">return</span> <span class="n">f</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">decorator</span><span class="p">(</span><span class="n">__generic_parameters_of_f</span><span class="p">())</span>
</pre></div>
</div>
<p>Generic classes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">Base</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">def695</span> <span class="n">__generic_parameters_of_C</span><span class="p">():</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;T&#39;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="n">__type_params__</span> <span class="o">=</span> <span class="p">(</span><span class="n">T</span><span class="p">,)</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">return</span> <span class="n">C</span>
<span class="n">C</span> <span class="o">=</span> <span class="n">__generic_parameters_of_C</span><span class="p">()</span>
</pre></div>
</div>
<p>The biggest divergence from existing behavior for <code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes
is the behavior within class scopes. This divergence is necessary
so that generics defined within classes behave in an intuitive way:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="k">class</span> <span class="nc">Nested</span><span class="p">:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">generic_method</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">Nested</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>Equivalent to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="k">class</span> <span class="nc">Nested</span><span class="p">:</span> <span class="o">...</span>
<span class="n">def695</span> <span class="n">__generic_parameters_of_generic_method</span><span class="p">():</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">typing</span><span class="o">.</span><span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;T&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">generic_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">Nested</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span>
<span class="k">return</span> <span class="n">generic_method</span>
<span class="n">generic_method</span> <span class="o">=</span> <span class="n">__generic_parameters_of_generic_method</span><span class="p">()</span>
</pre></div>
</div>
<p>In this example, the annotations for <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> are evaluated within
a <code class="docutils literal notranslate"><span class="pre">def695</span></code> scope, because they need access to the type parameter <code class="docutils literal notranslate"><span class="pre">T</span></code>
for the generic method. However, they also need access to the <code class="docutils literal notranslate"><span class="pre">Nested</span></code>
name defined within the class namespace. If <code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes behaved
like regular function scopes, <code class="docutils literal notranslate"><span class="pre">Nested</span></code> would not be visible within the
function scope. Therefore, <code class="docutils literal notranslate"><span class="pre">def695</span></code> scopes that are immediately within
class scopes have access to that class scope, as described above.</p>
</section>
<section id="library-changes">
<h3><a class="toc-backref" href="#library-changes" role="doc-backlink">Library Changes</a></h3>
<p>Several classes in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module that are currently implemented in
Python must be partially implemented in C. This includes <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>,
<code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>, <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code>, and <code class="docutils literal notranslate"><span class="pre">Generic</span></code>, and the new class
<code class="docutils literal notranslate"><span class="pre">TypeAliasType</span></code> (described above). The implementation may delegate to the
Python version of <code class="docutils literal notranslate"><span class="pre">typing.py</span></code> for some behaviors that interact heavily with
the rest of the module. The
documented behaviors of these classes should not change.</p>
</section>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>This proposal is prototyped in
<a class="reference external" href="https://github.com/python/cpython/pull/103764">CPython PR #103764</a>.</p>
<p>The Pyright type checker supports the behavior described in this PEP.</p>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
<section id="prefix-clause">
<h3><a class="toc-backref" href="#prefix-clause" role="doc-backlink">Prefix Clause</a></h3>
<p>We explored various syntactic options for specifying type parameters that
preceded <code class="docutils literal notranslate"><span class="pre">def</span></code> and <code class="docutils literal notranslate"><span class="pre">class</span></code> statements. One such variant we considered
used a <code class="docutils literal notranslate"><span class="pre">using</span></code> clause as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">using</span> <span class="n">S</span><span class="p">,</span> <span class="n">T</span>
<span class="k">class</span> <span class="nc">ClassA</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>This option was rejected because the scoping rules for the type parameters
were less clear. Also, this syntax did not interact well with class and
function decorators, which are common in Python. Only one other popular
programming language, C++, uses this approach.</p>
<p>We likewise considered prefix forms that looked like decorators (e.g.,
<code class="docutils literal notranslate"><span class="pre">&#64;using(S,</span> <span class="pre">T)</span></code>). This idea was rejected because such forms would be confused
with regular decorators, and they would not compose well with existing
decorators. Furthermore, decorators are logically executed after the statement
they are decorating, so it would be confusing for them to introduce symbols
(type parameters) that are visible within the “decorated” statement, which is
logically executed before the decorator itself.</p>
</section>
<section id="angle-brackets">
<h3><a class="toc-backref" href="#angle-brackets" role="doc-backlink">Angle Brackets</a></h3>
<p>Many languages that support generics make use of angle brackets. (Refer to
the table at the end of Appendix A for a summary.) We explored the use of
angle brackets for type parameter declarations in Python, but we ultimately
rejected it for two reasons. First, angle brackets are not considered
“paired” by the Python scanner, so end-of-line characters between a <code class="docutils literal notranslate"><span class="pre">&lt;</span></code>
and <code class="docutils literal notranslate"><span class="pre">&gt;</span></code> token are retained. That means any line breaks within a list of
type parameters would require the use of unsightly and cumbersome <code class="docutils literal notranslate"><span class="pre">\</span></code> escape
sequences. Second, Python has already established the use of square brackets
for explicit specialization of a generic type (e.g., <code class="docutils literal notranslate"><span class="pre">list[int]</span></code>). We
concluded that it would be inconsistent and confusing to use angle brackets
for generic declarations but square brackets for explicit specialization. All
other languages that we surveyed were consistent in this regard.</p>
</section>
<section id="bounds-syntax">
<h3><a class="toc-backref" href="#bounds-syntax" role="doc-backlink">Bounds Syntax</a></h3>
<p>We explored various syntactic options for specifying the bounds and constraints
for a type variable. We considered, but ultimately rejected, the use
of a <code class="docutils literal notranslate"><span class="pre">&lt;:</span></code> token like in Scala, the use of an <code class="docutils literal notranslate"><span class="pre">extends</span></code> or <code class="docutils literal notranslate"><span class="pre">with</span></code>
keyword like in various other languages, and the use of a function call
syntax similar to todays <code class="docutils literal notranslate"><span class="pre">typing.TypeVar</span></code> constructor. The simple colon
syntax is consistent with many other programming languages (see Appendix A),
and it was heavily preferred by a cross section of Python developers who
were surveyed.</p>
</section>
<section id="explicit-variance">
<h3><a class="toc-backref" href="#explicit-variance" role="doc-backlink">Explicit Variance</a></h3>
<p>We considered adding syntax for specifying whether a type parameter is intended
to be invariant, covariant, or contravariant. The <code class="docutils literal notranslate"><span class="pre">typing.TypeVar</span></code> mechanism
in Python requires this. A few other languages including Scala and C#
also require developers to specify the variance. We rejected this idea because
variance can generally be inferred, and most modern programming languages
do infer variance based on usage. Variance is an advanced topic that
many developers find confusing, so we want to eliminate the need to
understand this concept for most Python developers.</p>
</section>
<section id="name-mangling">
<h3><a class="toc-backref" href="#name-mangling" role="doc-backlink">Name Mangling</a></h3>
<p>When considering implementation options, we considered a “name mangling”
approach where each type parameter was given a unique “mangled” name by the
compiler. This mangled name would be based on the qualified name of the
generic class, function or type alias it was associated with. This approach
was rejected because qualified names are not necessarily unique, which means
the mangled name would need to be based on some other randomized value.
Furthermore, this approach is not compatible with techniques used for
evaluating quoted (forward referenced) type annotations.</p>
</section>
</section>
<section id="appendix-a-survey-of-type-parameter-syntax">
<h2><a class="toc-backref" href="#appendix-a-survey-of-type-parameter-syntax" role="doc-backlink">Appendix A: Survey of Type Parameter Syntax</a></h2>
<p>Support for generic types is found in many programming languages. In this
section, we provide a survey of the options used by other popular programming
languages. This is relevant because familiarity with other languages will
make it easier for Python developers to understand this concept. We provide
additional details here (for example, default type argument support) that
may be useful when considering future extensions to the Python type system.</p>
<section id="c">
<h3><a class="toc-backref" href="#c" role="doc-backlink">C++</a></h3>
<p>C++ uses angle brackets in combination with keywords <code class="docutils literal notranslate"><span class="pre">template</span></code> and
<code class="docutils literal notranslate"><span class="pre">typename</span></code> to declare type parameters. It uses angle brackets for
specialization.</p>
<p>C++20 introduced the notion of generalized constraints, which can act
like protocols in Python. A collection of constraints can be defined in
a named entity called a <code class="docutils literal notranslate"><span class="pre">concept</span></code>.</p>
<p>Variance is not explicitly specified, but constraints can enforce variance.</p>
<p>A default type argument can be specified using the <code class="docutils literal notranslate"><span class="pre">=</span></code> operator.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="k">template</span><span class="w"> </span><span class="o">&lt;</span><span class="k">typename</span><span class="o">&gt;</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ClassA</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// Constraints are supported through compile-time assertions.</span>
<span class="w"> </span><span class="k">static_assert</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_base_of</span><span class="o">&lt;</span><span class="n">BaseClass</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">);</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="n">Container</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">t</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// Generic function with default type argument</span>
<span class="k">template</span><span class="w"> </span><span class="o">&lt;</span><span class="k">typename</span><span class="w"> </span><span class="nc">S</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">int</span><span class="o">&gt;</span>
<span class="n">S</span><span class="w"> </span><span class="n">func1</span><span class="p">(</span><span class="n">ClassA</span><span class="o">&lt;</span><span class="n">S</span><span class="o">&gt;</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"> </span><span class="p">{};</span>
<span class="c1">// C++20 introduced a more generalized notion of &quot;constraints&quot;</span>
<span class="c1">// and &quot;concepts&quot;, which are named constraints.</span>
<span class="c1">// A sample concept</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">&gt;</span>
<span class="k">concept</span><span class="w"> </span><span class="nc">Hashable</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">requires</span><span class="p">(</span><span class="n">T</span><span class="w"> </span><span class="n">a</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">hash</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">{}(</span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">convertible_to</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// Use of a concept in a template</span>
<span class="k">template</span><span class="o">&lt;</span><span class="n">Hashable</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span>
<span class="kt">void</span><span class="w"> </span><span class="n">func2</span><span class="p">(</span><span class="n">T</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span>
<span class="c1">// Alternative use of concept</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">&gt;</span><span class="w"> </span><span class="k">requires</span><span class="w"> </span><span class="n">Hashable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="kt">void</span><span class="w"> </span><span class="n">func3</span><span class="p">(</span><span class="n">T</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span>
<span class="c1">// Alternative use of concept</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">&gt;</span>
<span class="kt">void</span><span class="w"> </span><span class="n">func3</span><span class="p">(</span><span class="n">T</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="k">requires</span><span class="w"> </span><span class="n">Hashable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span>
</pre></div>
</div>
</section>
<section id="java">
<h3><a class="toc-backref" href="#java" role="doc-backlink">Java</a></h3>
<p>Java uses angle brackets to declare type parameters and for specialization.
By default, type parameters are invariant.
The <code class="docutils literal notranslate"><span class="pre">extends</span></code> keyword is used to specify an upper bound. The <code class="docutils literal notranslate"><span class="pre">super</span></code> keyword
is used to specify a contravariant bound.</p>
<p>Java uses use-site variance. The compiler places limits on which methods and
members can be accessed based on the use of a generic type. Variance is
not specified explicitly.</p>
<p>Java provides no way to specify a default type argument.</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">ClassA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">Container</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">t</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Generic method</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="o">&lt;</span><span class="n">S</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">Number</span><span class="o">&gt;</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">method1</span><span class="p">(</span><span class="n">S</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// Use site variance</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">method1</span><span class="p">(</span><span class="n">ClassA</span><span class="o">&lt;?</span><span class="w"> </span><span class="kd">super</span><span class="w"> </span><span class="n">Integer</span><span class="o">&gt;</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
<section id="id2">
<h3><a class="toc-backref" href="#id2" role="doc-backlink">C#</a></h3>
<p>C# uses angle brackets to declare type parameters and for specialization.
The <code class="docutils literal notranslate"><span class="pre">where</span></code> keyword and a colon is used to specify the bound for a type
parameter.</p>
<p>C# uses declaration-site variance using the keywords <code class="docutils literal notranslate"><span class="pre">in</span></code> and <code class="docutils literal notranslate"><span class="pre">out</span></code> for
contravariance and covariance, respectively. By default, type parameters are
invariant.</p>
<p>C# provides no way to specify a default type argument.</p>
<div class="highlight-c# notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class with bounds on type parameters</span>
<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">ClassA</span><span class="o">&lt;</span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span>
<span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">SomeClass1</span>
<span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">SomeClass2</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// Generic method</span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="n">MyMethod</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span><span class="p">(</span><span class="n">U</span><span class="w"> </span><span class="k">value</span><span class="p">)</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">U</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">SomeClass3</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Contravariant and covariant type parameters</span>
<span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="nc">ClassB</span><span class="o">&lt;</span><span class="k">in</span><span class="w"> </span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="k">out</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="nf">MyMethod</span><span class="p">(</span><span class="n">S</span><span class="w"> </span><span class="k">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
<section id="typescript">
<h3><a class="toc-backref" href="#typescript" role="doc-backlink">TypeScript</a></h3>
<p>TypeScript uses angle brackets to declare type parameters and for
specialization. The <code class="docutils literal notranslate"><span class="pre">extends</span></code> keyword is used to specify a bound. It can be
combined with other type operators such as <code class="docutils literal notranslate"><span class="pre">keyof</span></code>.</p>
<p>TypeScript uses declaration-site variance. Variance is inferred from
usage, not specified explicitly. TypeScript 4.7 introduced the ability
to specify variance using <code class="docutils literal notranslate"><span class="pre">in</span></code> and <code class="docutils literal notranslate"><span class="pre">out</span></code> keywords. This was added to handle
extremely complex types where inference of variance was expensive.</p>
<p>A default type argument can be specified using the <code class="docutils literal notranslate"><span class="pre">=</span></code> operator.</p>
<p>TypeScript supports the <code class="docutils literal notranslate"><span class="pre">type</span></code> keyword to declare a type alias, and this
syntax supports generics.</p>
<div class="highlight-typescript notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic interface</span>
<span class="kd">interface</span><span class="w"> </span><span class="nx">InterfaceA</span><span class="o">&lt;</span><span class="nx">S</span><span class="p">,</span><span class="w"> </span><span class="nx">T</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">SomeInterface1</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">val1</span><span class="o">:</span><span class="w"> </span><span class="kt">S</span><span class="p">;</span>
<span class="w"> </span><span class="nx">val2</span><span class="o">:</span><span class="w"> </span><span class="kt">T</span><span class="p">;</span>
<span class="w"> </span><span class="nx">method1</span><span class="o">&lt;</span><span class="nx">U</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">SomeInterface2</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">val</span><span class="o">:</span><span class="w"> </span><span class="kt">U</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="nx">S</span>
<span class="p">}</span>
<span class="c1">// Generic function</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">func1</span><span class="o">&lt;</span><span class="nx">T</span><span class="p">,</span><span class="w"> </span><span class="nx">K</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">keyof</span><span class="w"> </span><span class="nx">T</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">ojb</span><span class="o">:</span><span class="w"> </span><span class="kt">T</span><span class="p">,</span><span class="w"> </span><span class="nx">key</span><span class="o">:</span><span class="w"> </span><span class="kt">K</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Contravariant and covariant type parameters (TypeScript 4.7)</span>
<span class="kd">interface</span><span class="w"> </span><span class="nx">InterfaceB</span><span class="o">&lt;</span><span class="ow">in</span><span class="w"> </span><span class="nx">S</span><span class="p">,</span><span class="w"> </span><span class="nx">out</span><span class="w"> </span><span class="nx">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Type parameter with default</span>
<span class="kd">interface</span><span class="w"> </span><span class="nx">InterfaceC</span><span class="o">&lt;</span><span class="nx">T</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">SomeInterface3</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Generic type alias</span>
<span class="kr">type</span><span class="w"> </span><span class="nx">MyType</span><span class="o">&lt;</span><span class="nx">T</span><span class="w"> </span><span class="k">extends</span><span class="w"> </span><span class="nx">SomeInterface4</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Array</span><span class="o">&lt;</span><span class="nx">T</span><span class="o">&gt;</span>
</pre></div>
</div>
</section>
<section id="scala">
<h3><a class="toc-backref" href="#scala" role="doc-backlink">Scala</a></h3>
<p>In Scala, square brackets are used to declare type parameters. Square
brackets are also used for specialization. The <code class="docutils literal notranslate"><span class="pre">&lt;:</span></code> and <code class="docutils literal notranslate"><span class="pre">&gt;:</span></code> operators
are used to specify upper and lower bounds, respectively.</p>
<p>Scala uses use-site variance but also allows declaration-site variance
specification. It uses a <code class="docutils literal notranslate"><span class="pre">+</span></code> or <code class="docutils literal notranslate"><span class="pre">-</span></code> prefix operator for covariance and
contravariance, respectively.</p>
<p>Scala provides no way to specify a default type argument.</p>
<p>It does support higher-kinded types (type parameters that accept type
type parameters).</p>
<div class="highlight-scala notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class; type parameter has upper bound</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ClassA</span><span class="p">[</span><span class="nc">A</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="nc">SomeClass1</span><span class="p">]</span>
<span class="p">{</span>
<span class="w"> </span><span class="c1">// Generic method; type parameter has lower bound</span>
<span class="w"> </span><span class="k">def</span><span class="w"> </span><span class="nf">method1</span><span class="p">[</span><span class="nc">B</span><span class="w"> </span><span class="o">&gt;:</span><span class="w"> </span><span class="nc">A</span><span class="p">](</span><span class="kd">val</span><span class="p">:</span><span class="w"> </span><span class="nc">B</span><span class="p">)</span><span class="w"> </span><span class="p">...</span>
<span class="p">}</span>
<span class="c1">// Use of an upper and lower bound with the same type parameter</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ClassB</span><span class="p">[</span><span class="nc">A</span><span class="w"> </span><span class="o">&gt;:</span><span class="w"> </span><span class="nc">SomeClass1</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="nc">SomeClass2</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Contravariant and covariant type parameters</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ClassC</span><span class="p">[</span><span class="o">+</span><span class="nc">A</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="nc">B</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Higher-kinded type</span>
<span class="k">trait</span><span class="w"> </span><span class="nc">Collection</span><span class="p">[</span><span class="nc">T</span><span class="p">[</span><span class="n">_</span><span class="p">]]</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">def</span><span class="w"> </span><span class="nf">method1</span><span class="p">[</span><span class="nc">A</span><span class="p">](</span><span class="n">a</span><span class="p">:</span><span class="w"> </span><span class="nc">A</span><span class="p">):</span><span class="w"> </span><span class="nc">T</span><span class="p">[</span><span class="nc">A</span><span class="p">]</span>
<span class="w"> </span><span class="k">def</span><span class="w"> </span><span class="nf">method2</span><span class="p">[</span><span class="nc">B</span><span class="p">](</span><span class="n">b</span><span class="p">:</span><span class="w"> </span><span class="nc">T</span><span class="p">[</span><span class="nc">B</span><span class="p">]):</span><span class="w"> </span><span class="nc">B</span>
<span class="p">}</span>
<span class="c1">// Generic type alias</span>
<span class="k">type</span><span class="w"> </span><span class="nc">MyType</span><span class="p">[</span><span class="nc">T</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="nc">Int</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nc">Container</span><span class="p">[</span><span class="nc">T</span><span class="p">]</span>
</pre></div>
</div>
</section>
<section id="swift">
<h3><a class="toc-backref" href="#swift" role="doc-backlink">Swift</a></h3>
<p>Swift uses angle brackets to declare type parameters and for specialization.
The upper bound of a type parameter is specified using a colon.</p>
<p>Swift doesnt support generic variance; all type parameters are invariant.</p>
<p>Swift provides no way to specify a default type argument.</p>
<div class="highlight-swift notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="kd">class</span> <span class="nc">ClassA</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="c1">// Generic method</span>
<span class="kd">func</span> <span class="nf">method1</span><span class="p">&lt;</span><span class="n">X</span><span class="p">&gt;(</span><span class="n">val</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="n">X</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Type parameter with upper bound constraint</span>
<span class="kd">class</span> <span class="nc">ClassB</span><span class="p">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">SomeClass1</span><span class="p">&gt;</span> <span class="p">{}</span>
<span class="c1">// Generic type alias</span>
<span class="kd">typealias</span> <span class="n">MyType</span><span class="p">&lt;</span><span class="n">A</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">Container</span><span class="p">&lt;</span><span class="n">A</span><span class="p">&gt;</span>
</pre></div>
</div>
</section>
<section id="rust">
<h3><a class="toc-backref" href="#rust" role="doc-backlink">Rust</a></h3>
<p>Rust uses angle brackets to declare type parameters and for specialization.
The upper bound of a type parameter is specified using a colon. Alternatively
a <code class="docutils literal notranslate"><span class="pre">where</span></code> clause can specify various constraints.</p>
<p>Rust does not have traditional object oriented inheritance or variance.
Subtyping in Rust is very restricted and occurs only due to variance with
respect to lifetimes.</p>
<p>A default type argument can be specified using the <code class="docutils literal notranslate"><span class="pre">=</span></code> operator.</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">StructA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// T&#39;s lifetime is inferred as covariant</span>
<span class="w"> </span><span class="n">x</span><span class="p">:</span><span class="w"> </span><span class="nc">T</span>
<span class="p">}</span>
<span class="k">fn</span><span class="w"> </span><span class="nf">f</span><span class="o">&lt;&#39;</span><span class="na">a</span><span class="o">&gt;</span><span class="p">(</span>
<span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">short_lifetime</span><span class="p">:</span><span class="w"> </span><span class="nc">StructA</span><span class="o">&lt;&amp;&#39;</span><span class="na">a</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">long_lifetime</span><span class="p">:</span><span class="w"> </span><span class="nc">StructA</span><span class="o">&lt;&amp;&#39;</span><span class="nb">static</span><span class="w"> </span><span class="kt">i32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">long_lifetime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">short_lifetime</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// error: StructA&lt;&amp;&#39;a i32&gt; is not a subtype of StructA&lt;&amp;&#39;static i32&gt;</span>
<span class="w"> </span><span class="n">short_lifetime</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">long_lifetime</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// valid: StructA&lt;&amp;&#39;static i32&gt; is a subtype of StructA&lt;&amp;&#39;a i32&gt;</span>
<span class="p">}</span>
<span class="c1">// Type parameter with bound</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">StructB</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span><span class="w"> </span><span class="nc">SomeTrait</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span>
<span class="c1">// Type parameter with additional constraints</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">StructC</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="k">where</span>
<span class="w"> </span><span class="n">T</span><span class="p">:</span><span class="w"> </span><span class="nb">Iterator</span><span class="p">,</span>
<span class="w"> </span><span class="n">T</span><span class="p">::</span><span class="n">Item</span><span class="p">:</span><span class="w"> </span><span class="nb">Copy</span>
<span class="p">{}</span>
<span class="c1">// Generic function</span>
<span class="k">fn</span><span class="w"> </span><span class="nf">func1</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">val</span><span class="p">:</span><span class="w"> </span><span class="kp">&amp;</span><span class="p">[</span><span class="n">T</span><span class="p">])</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="nc">T</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Generic type alias</span>
<span class="k">type</span><span class="w"> </span><span class="nc">MyType</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">StructC</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
</pre></div>
</div>
</section>
<section id="kotlin">
<h3><a class="toc-backref" href="#kotlin" role="doc-backlink">Kotlin</a></h3>
<p>Kotlin uses angle brackets to declare type parameters and for specialization.
By default, type parameters are invariant. The upper bound of a type is
specified using a colon.
Alternatively, a <code class="docutils literal notranslate"><span class="pre">where</span></code> clause can specify various constraints.</p>
<p>Kotlin supports declaration-site variance where variance of type parameters is
explicitly declared using <code class="docutils literal notranslate"><span class="pre">in</span></code> and <code class="docutils literal notranslate"><span class="pre">out</span></code> keywords. It also supports use-site
variance which limits which methods and members can be used.</p>
<p>Kotlin provides no way to specify a default type argument.</p>
<div class="highlight-kotlin notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="c1">// Type parameter with upper bound</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassB</span><span class="o">&lt;</span><span class="n">T</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">SomeClass1</span><span class="o">&gt;</span>
<span class="c1">// Contravariant and covariant type parameters</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassC</span><span class="o">&lt;</span><span class="k">in</span><span class="w"> </span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="k">out</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span>
<span class="c1">// Generic function</span>
<span class="kd">fun</span><span class="w"> </span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="nf">func1</span><span class="p">():</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Use site variance</span>
<span class="w"> </span><span class="kd">val</span><span class="w"> </span><span class="nv">covariantA</span><span class="p">:</span><span class="w"> </span><span class="n">ClassA</span><span class="o">&lt;</span><span class="k">out</span><span class="w"> </span><span class="n">Number</span><span class="o">&gt;</span>
<span class="w"> </span><span class="kd">val</span><span class="w"> </span><span class="nv">contravariantA</span><span class="p">:</span><span class="w"> </span><span class="n">ClassA</span><span class="o">&lt;</span><span class="k">in</span><span class="w"> </span><span class="n">Number</span><span class="o">&gt;</span>
<span class="p">}</span>
<span class="c1">// Generic type alias</span>
<span class="k">typealias</span><span class="w"> </span><span class="n">TypeAliasFoo</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ClassA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
</pre></div>
</div>
</section>
<section id="julia">
<h3><a class="toc-backref" href="#julia" role="doc-backlink">Julia</a></h3>
<p>Julia uses curly braces to declare type parameters and for specialization.
The <code class="docutils literal notranslate"><span class="pre">&lt;:</span></code> operator can be used within a <code class="docutils literal notranslate"><span class="pre">where</span></code> clause to declare
upper and lower bounds on a type.</p>
<div class="highlight-julia notranslate"><div class="highlight"><pre><span></span><span class="c"># Generic struct; type parameter with upper and lower bounds</span>
<span class="c"># Valid for T in (Int64, Signed, Integer, Real, Number)</span>
<span class="k">struct</span> <span class="kt">Container</span><span class="p">{</span><span class="kt">Int</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="kt">Number</span><span class="p">}</span>
<span class="w"> </span><span class="n">x</span><span class="o">::</span><span class="kt">T</span>
<span class="k">end</span>
<span class="c"># Generic function</span>
<span class="k">function</span><span class="w"> </span><span class="n">func1</span><span class="p">(</span><span class="n">v</span><span class="o">::</span><span class="kt">Container</span><span class="p">{</span><span class="kt">T</span><span class="p">})</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="kt">Real</span><span class="w"> </span><span class="k">end</span>
<span class="c"># Alternate forms of generic function</span>
<span class="k">function</span><span class="w"> </span><span class="n">func2</span><span class="p">(</span><span class="n">v</span><span class="o">::</span><span class="kt">Container</span><span class="p">{</span><span class="kt">T</span><span class="p">}</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="o">&lt;:</span><span class="w"> </span><span class="kt">Real</span><span class="p">)</span><span class="w"> </span><span class="k">end</span>
<span class="k">function</span><span class="w"> </span><span class="n">func3</span><span class="p">(</span><span class="n">v</span><span class="o">::</span><span class="kt">Container</span><span class="p">{</span><span class="o">&lt;:</span><span class="w"> </span><span class="kt">Real</span><span class="p">})</span><span class="w"> </span><span class="k">end</span>
<span class="c"># Tuple types are covariant</span>
<span class="c"># Valid for func4((2//3, 3.5))</span>
<span class="k">function</span><span class="w"> </span><span class="n">func4</span><span class="p">(</span><span class="n">t</span><span class="o">::</span><span class="kt">Tuple</span><span class="p">{</span><span class="kt">Real</span><span class="p">,</span><span class="kt">Real</span><span class="p">})</span><span class="w"> </span><span class="k">end</span>
</pre></div>
</div>
</section>
<section id="dart">
<h3><a class="toc-backref" href="#dart" role="doc-backlink">Dart</a></h3>
<p>Dart uses angle brackets to declare type parameters and for specialization.
The upper bound of a type is specified using the <code class="docutils literal notranslate"><span class="pre">extends</span></code> keyword.
By default, type parameters are covariant.</p>
<p>Dart supports declaration-site variance, where variance of type parameters is
explicitly declared using <code class="docutils literal notranslate"><span class="pre">in</span></code>, <code class="docutils literal notranslate"><span class="pre">out</span></code> and <code class="docutils literal notranslate"><span class="pre">inout</span></code> keywords.
It does not support use-site variance.</p>
<p>Dart provides no way to specify a default type argument.</p>
<div class="highlight-dart notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic class</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Type parameter with upper bound</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassB</span><span class="o">&lt;</span><span class="n">T</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">SomeClass1</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Contravariant and covariant type parameters</span>
<span class="kd">class</span><span class="w"> </span><span class="nc">ClassC</span><span class="o">&lt;</span><span class="k">in</span><span class="w"> </span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Generic function</span>
<span class="n">T</span><span class="w"> </span><span class="n">func1</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Generic type alias</span>
<span class="kd">typedef</span><span class="w"> </span><span class="n">TypeDefFoo</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ClassA</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
</pre></div>
</div>
</section>
<section id="go">
<h3><a class="toc-backref" href="#go" role="doc-backlink">Go</a></h3>
<p>Go uses square brackets to declare type parameters and for specialization.
The upper bound of a type is specified after the name of the parameter, and
must always be specified. The keyword <code class="docutils literal notranslate"><span class="pre">any</span></code> is used for an unbound type parameter.</p>
<p>Go doesnt support variance; all type parameters are invariant.</p>
<p>Go provides no way to specify a default type argument.</p>
<p>Go does not support generic type aliases.</p>
<div class="highlight-go notranslate"><div class="highlight"><pre><span></span><span class="c1">// Generic type without a bound</span>
<span class="kd">type</span><span class="w"> </span><span class="nx">TypeA</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="nx">T</span>
<span class="p">}</span>
<span class="c1">// Type parameter with upper bound</span>
<span class="kd">type</span><span class="w"> </span><span class="nx">TypeB</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="nx">SomeType1</span><span class="p">]</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<span class="c1">// Generic function</span>
<span class="kd">func</span><span class="w"> </span><span class="nx">func1</span><span class="p">[</span><span class="nx">T</span><span class="w"> </span><span class="kt">any</span><span class="p">]()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
</pre></div>
</div>
</section>
<section id="summary">
<h3><a class="toc-backref" href="#summary" role="doc-backlink">Summary</a></h3>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"></th>
<th class="head">Decl
Syntax</th>
<th class="head">Upper
Bound</th>
<th class="head">Lower
Bound</th>
<th class="head">Default
Value</th>
<th class="head">Variance
Site</th>
<th class="head">Variance</th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td>C++</td>
<td>template
&lt;&gt;</td>
<td>n/a</td>
<td>n/a</td>
<td>=</td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr class="row-odd"><td>Java</td>
<td>&lt;&gt;</td>
<td>extends</td>
<td></td>
<td></td>
<td>use</td>
<td>super,
extends</td>
</tr>
<tr class="row-even"><td>C#</td>
<td>&lt;&gt;</td>
<td>where</td>
<td></td>
<td></td>
<td>decl</td>
<td>in, out</td>
</tr>
<tr class="row-odd"><td>TypeScript</td>
<td>&lt;&gt;</td>
<td>extends</td>
<td></td>
<td>=</td>
<td>decl</td>
<td>inferred,
in, out</td>
</tr>
<tr class="row-even"><td>Scala</td>
<td>[]</td>
<td>T &lt;: X</td>
<td>T &gt;: X</td>
<td></td>
<td>use, decl</td>
<td>+, -</td>
</tr>
<tr class="row-odd"><td>Swift</td>
<td>&lt;&gt;</td>
<td>T: X</td>
<td></td>
<td></td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr class="row-even"><td>Rust</td>
<td>&lt;&gt;</td>
<td>T: X,
where</td>
<td></td>
<td>=</td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr class="row-odd"><td>Kotlin</td>
<td>&lt;&gt;</td>
<td>T: X,
where</td>
<td></td>
<td></td>
<td>use, decl</td>
<td>in, out</td>
</tr>
<tr class="row-even"><td>Julia</td>
<td>{}</td>
<td>T &lt;: X</td>
<td>X &lt;: T</td>
<td></td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr class="row-odd"><td>Dart</td>
<td>&lt;&gt;</td>
<td>extends</td>
<td></td>
<td></td>
<td>decl</td>
<td>in, out,
inout</td>
</tr>
<tr class="row-even"><td>Go</td>
<td>[]</td>
<td>T X</td>
<td></td>
<td></td>
<td>n/a</td>
<td>n/a</td>
</tr>
<tr class="row-odd"><td>Python
(proposed)</td>
<td>[]</td>
<td>T: X</td>
<td></td>
<td></td>
<td>decl</td>
<td>inferred</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>Thanks to Sebastian Rittau for kick-starting the discussions that led to this
proposal, to Jukka Lehtosalo for proposing the syntax for type alias
statements and to Jelle Zijlstra, Daniel Moisset, and Guido van Rossum
for their valuable feedback and suggested improvements to the specification
and implementation.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document is placed in the public domain or under the CC0-1.0-Universal
license, whichever is more permissive.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0695.rst">https://github.com/python/peps/blob/main/peps/pep-0695.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0695.rst">2024-02-17 03:25:41 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
<li><a class="reference internal" href="#points-of-confusion">Points of Confusion</a></li>
</ul>
</li>
<li><a class="reference internal" href="#summary-examples">Summary Examples</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#type-parameter-declarations">Type Parameter Declarations</a></li>
<li><a class="reference internal" href="#upper-bound-specification">Upper Bound Specification</a></li>
<li><a class="reference internal" href="#constrained-type-specification">Constrained Type Specification</a></li>
<li><a class="reference internal" href="#runtime-representation-of-bounds-and-constraints">Runtime Representation of Bounds and Constraints</a></li>
<li><a class="reference internal" href="#generic-type-alias">Generic Type Alias</a></li>
<li><a class="reference internal" href="#runtime-type-alias-class">Runtime Type Alias Class</a></li>
<li><a class="reference internal" href="#type-parameter-scopes">Type Parameter Scopes</a></li>
<li><a class="reference internal" href="#accessing-type-parameters-at-runtime">Accessing Type Parameters at Runtime</a></li>
<li><a class="reference internal" href="#variance-inference">Variance Inference</a></li>
<li><a class="reference internal" href="#auto-variance-for-typevar">Auto Variance For TypeVar</a></li>
<li><a class="reference internal" href="#compatibility-with-traditional-typevars">Compatibility with Traditional TypeVars</a></li>
</ul>
</li>
<li><a class="reference internal" href="#runtime-implementation">Runtime Implementation</a><ul>
<li><a class="reference internal" href="#grammar-changes">Grammar Changes</a></li>
<li><a class="reference internal" href="#ast-changes">AST Changes</a></li>
<li><a class="reference internal" href="#lazy-evaluation">Lazy Evaluation</a></li>
<li><a class="reference internal" href="#scoping-behavior">Scoping Behavior</a></li>
<li><a class="reference internal" href="#library-changes">Library Changes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#prefix-clause">Prefix Clause</a></li>
<li><a class="reference internal" href="#angle-brackets">Angle Brackets</a></li>
<li><a class="reference internal" href="#bounds-syntax">Bounds Syntax</a></li>
<li><a class="reference internal" href="#explicit-variance">Explicit Variance</a></li>
<li><a class="reference internal" href="#name-mangling">Name Mangling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-survey-of-type-parameter-syntax">Appendix A: Survey of Type Parameter Syntax</a><ul>
<li><a class="reference internal" href="#c">C++</a></li>
<li><a class="reference internal" href="#java">Java</a></li>
<li><a class="reference internal" href="#id2">C#</a></li>
<li><a class="reference internal" href="#typescript">TypeScript</a></li>
<li><a class="reference internal" href="#scala">Scala</a></li>
<li><a class="reference internal" href="#swift">Swift</a></li>
<li><a class="reference internal" href="#rust">Rust</a></li>
<li><a class="reference internal" href="#kotlin">Kotlin</a></li>
<li><a class="reference internal" href="#julia">Julia</a></li>
<li><a class="reference internal" href="#dart">Dart</a></li>
<li><a class="reference internal" href="#go">Go</a></li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0695.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>