1707 lines
160 KiB
HTML
1707 lines
160 KiB
HTML
|
|
|||
|
<!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> » </li>
|
|||
|
<li><a href="../pep-0000/">PEP Index</a> » </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 <erictr at microsoft.com></dd>
|
|||
|
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
|
|||
|
<dd class="field-even">Guido van Rossum <guido at python.org></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@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@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("T")</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">"_T_co"</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">-></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">-></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">"_T"</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">-></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">-></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">"_T"</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">"ForwardReference"</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">"ForwardReference"</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">"Vegetable"</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">"T"</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: 'T' 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: 'T' 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">-></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: 'T' 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: 'T' 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: 'T' 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 'Private' 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, 'Inner' 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">-></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"># "type parameter 'T' already in use" because they are using the</span>
|
|||
|
<span class="c1"># type parameter 'T', which is already in use by the outer scope</span>
|
|||
|
<span class="c1"># 'ClassA'.</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 'x' 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 'x' 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 'Outer'</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 'Inner1'</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 'Outer';</span>
|
|||
|
<span class="c1"># If 'Outer' did not use the new type parameter syntax,</span>
|
|||
|
<span class="c1"># this would instead refer to the global variable 'T'</span>
|
|||
|
<span class="nb">print</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="c1"># Prints 'T'</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 'outer_method'</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 'outer_method'</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">-></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. We’ll 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 parameter’s
|
|||
|
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">-></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">-></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">"T1"</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">"T2"</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">"T3"</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">"K"</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 "method1" is OK because it uses the</span>
|
|||
|
<span class="c1"># "traditional" 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 "method1".</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">-></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 "method2". 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 "method2", 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">-></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">'['</span> <span class="n">t</span><span class="o">=</span><span class="n">type_param_seq</span> <span class="s1">']'</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">','</span><span class="o">.</span><span class="n">type_param</span><span class="o">+</span> <span class="p">[</span><span class="s1">','</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">'*'</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span>
|
|||
|
<span class="o">|</span> <span class="s1">'**'</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">":"</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">'class'</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">'def'</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">"type"</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">'='</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 649’s <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 649’s “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 "int"</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 "str"</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">'Alias'</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">'T'</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">'Alias'</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">-></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">'T'</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">-></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">-></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">'T'</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">'U'</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">"Ts"</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">"P"</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">-></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">'T'</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">-></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">'T'</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">-></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">@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"><</span></code>
|
|||
|
and <code class="docutils literal notranslate"><span class="pre">></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"><:</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 today’s <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"><</span><span class="k">typename</span><span class="o">></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"><</span><span class="n">BaseClass</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">>::</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"><</span><span class="n">T</span><span class="o">></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"><</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">></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"><</span><span class="n">S</span><span class="o">></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 "constraints"</span>
|
|||
|
<span class="c1">// and "concepts", which are named constraints.</span>
|
|||
|
|
|||
|
<span class="c1">// A sample concept</span>
|
|||
|
<span class="k">template</span><span class="o"><</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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">-></span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">convertible_to</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="o">></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"><</span><span class="n">Hashable</span><span class="w"> </span><span class="n">T</span><span class="o">></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"><</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">></span><span class="w"> </span><span class="k">requires</span><span class="w"> </span><span class="n">Hashable</span><span class="o"><</span><span class="n">T</span><span class="o">></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"><</span><span class="k">typename</span><span class="w"> </span><span class="nc">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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"><</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">></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"><?</span><span class="w"> </span><span class="kd">super</span><span class="w"> </span><span class="n">Integer</span><span class="o">></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"><</span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">></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"><</span><span class="n">U</span><span class="o">></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"><</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">></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"><</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">></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"><</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">></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"><</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">></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"><</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">></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"><</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">></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"><</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">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Array</span><span class="o"><</span><span class="nx">T</span><span class="o">></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"><:</span></code> and <code class="docutils literal notranslate"><span class="pre">>:</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"><:</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">>:</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">>:</span><span class="w"> </span><span class="nc">SomeClass1</span><span class="w"> </span><span class="o"><:</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"><:</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 doesn’t 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"><</span><span class="n">T</span><span class="p">></span> <span class="p">{</span>
|
|||
|
<span class="c1">// Generic method</span>
|
|||
|
<span class="kd">func</span> <span class="nf">method1</span><span class="p"><</span><span class="n">X</span><span class="p">>(</span><span class="n">val</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="p">-></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"><</span><span class="n">T</span><span class="p">:</span> <span class="n">SomeClass1</span><span class="p">></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"><</span><span class="n">A</span><span class="p">></span> <span class="p">=</span> <span class="n">Container</span><span class="p"><</span><span class="n">A</span><span class="p">></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"><</span><span class="n">T</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// T'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"><'</span><span class="na">a</span><span class="o">></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"><&'</span><span class="na">a</span><span class="w"> </span><span class="kt">i32</span><span class="o">></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"><&'</span><span class="nb">static</span><span class="w"> </span><span class="kt">i32</span><span class="o">></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<&'a i32> is not a subtype of StructA<&'static i32></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<&'static i32> is a subtype of StructA<&'a i32></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"><</span><span class="n">T</span><span class="p">:</span><span class="w"> </span><span class="nc">SomeTrait</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="n">val</span><span class="p">:</span><span class="w"> </span><span class="kp">&</span><span class="p">[</span><span class="n">T</span><span class="p">])</span><span class="w"> </span><span class="p">-></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"><</span><span class="n">T</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">StructC</span><span class="o"><</span><span class="n">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></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"><</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">></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"><</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">></span>
|
|||
|
|
|||
|
<span class="c1">// Generic function</span>
|
|||
|
<span class="kd">fun</span><span class="w"> </span><span class="o"><</span><span class="n">T</span><span class="o">></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"><</span><span class="k">out</span><span class="w"> </span><span class="n">Number</span><span class="o">></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"><</span><span class="k">in</span><span class="w"> </span><span class="n">Number</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ClassA</span><span class="o"><</span><span class="n">T</span><span class="o">></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"><:</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"><:</span><span class="w"> </span><span class="kt">T</span><span class="w"> </span><span class="o"><:</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"><:</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"><:</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"><:</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"><</span><span class="n">T</span><span class="o">></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"><</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">></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"><</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">></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"><</span><span class="n">T</span><span class="o">></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"><</span><span class="n">T</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ClassA</span><span class="o"><</span><span class="n">T</span><span class="o">></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 doesn’t 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
|
|||
|
<></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><></td>
|
|||
|
<td>extends</td>
|
|||
|
<td></td>
|
|||
|
<td></td>
|
|||
|
<td>use</td>
|
|||
|
<td>super,
|
|||
|
extends</td>
|
|||
|
</tr>
|
|||
|
<tr class="row-even"><td>C#</td>
|
|||
|
<td><></td>
|
|||
|
<td>where</td>
|
|||
|
<td></td>
|
|||
|
<td></td>
|
|||
|
<td>decl</td>
|
|||
|
<td>in, out</td>
|
|||
|
</tr>
|
|||
|
<tr class="row-odd"><td>TypeScript</td>
|
|||
|
<td><></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 <: X</td>
|
|||
|
<td>T >: X</td>
|
|||
|
<td></td>
|
|||
|
<td>use, decl</td>
|
|||
|
<td>+, -</td>
|
|||
|
</tr>
|
|||
|
<tr class="row-odd"><td>Swift</td>
|
|||
|
<td><></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><></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><></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 <: X</td>
|
|||
|
<td>X <: T</td>
|
|||
|
<td></td>
|
|||
|
<td>n/a</td>
|
|||
|
<td>n/a</td>
|
|||
|
</tr>
|
|||
|
<tr class="row-odd"><td>Dart</td>
|
|||
|
<td><></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>
|