PEP 695: Fix/improve syntax & content of Language Survey section (#2725)

This commit is contained in:
KotlinIsland 2022-08-29 03:00:56 +10:00 committed by GitHub
parent 82072755b5
commit 754c8fb1f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 134 additions and 57 deletions

View File

@ -840,19 +840,19 @@ may be useful when considering future extensions to the Python type system.
C++
---
C++ uses angle brackets in combination with keywords "template" and
"typename" to declare type parameters. It uses angle brackets for
C++ uses angle brackets in combination with keywords ``template`` and
``typename`` to declare type parameters. It uses angle brackets for
specialization.
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 "concept".
a named entity called a ``concept``.
Variance is not explicitly specified, but constraints can enforce variance.
A default type argument can be specified using the "=" operator.
A default type argument can be specified using the ``=`` operator.
::
.. code-block:: c++
// Generic class
template <typename>
@ -896,7 +896,9 @@ Java
----
Java uses angle brackets to declare type parameters and for specialization.
The "extends" keyword is used to specify an upper bound.
By default, type parameters are invariant.
The ``extends`` keyword is used to specify an upper bound. The ``super`` keyword
is used to specify a contravariant bound.
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
@ -904,7 +906,7 @@ not specified explicitly.
Java provides no way to specify a default type argument.
::
.. code-block:: java
// Generic class
public class ClassA<T> {
@ -912,6 +914,9 @@ Java provides no way to specify a default type argument.
// Generic method
public <S extends Number> void method1(S value) { }
// Use site variance
public void method1(ClassA<? super Integer> value) { }
}
@ -919,16 +924,16 @@ C#
--
C# uses angle brackets to declare type parameters and for specialization.
The "where" keyword and a colon is used to specify the bound for a type
The ``where`` keyword and a colon is used to specify the bound for a type
parameter.
C# uses declaration-site variance using the keywords "in" and "out" for
C# uses declaration-site variance using the keywords ``in`` and ``out`` for
contravariance and covariance, respectively. By default, type parameters are
invariant.
C# provides no way to specify a default type argument.
::
.. code-block:: c#
// Generic class with bounds on type parameters
public class ClassA<S, T>
@ -951,20 +956,21 @@ TypeScript
----------
TypeScript uses angle brackets to declare type parameters and for
specialization. The "extends" keyword is used to specify a bound. It can be
combined with other type operators such as "keyof".
specialization. The ``extends`` keyword is used to specify a bound. It can be
combined with other type operators such as ``keyof``.
TypeScript uses declaration-site variance. Variance is inferred from
usage, not specified explicitly. TypeScript 4.7 will introduce the ability
to specify variance using "in" and "out" keywords. This was added to handle
extremely complex types where inference of variance was expensive.
usage, not specified explicitly. TypeScript 4.7 introduced the ability
to specify variance using ``in`` and ``out`` keywords. This was added to handle
extremely complex types where inference of variance was expensive,
yet the maintainers state that is useful for increasing readability.
A default type argument can be specified using the "=" operator.
A default type argument can be specified using the ``=`` operator.
TypeScript supports the "type" keyword to declare a type alias, and this
TypeScript supports the ``type`` keyword to declare a type alias, and this
syntax supports generics.
::
.. code-block:: typescript
// Generic interface
interface InterfaceA<S, T extends SomeInterface1> {
@ -991,11 +997,11 @@ Scala
-----
In Scala, square brackets are used to declare type parameters. Square
brackets are also used for specialization. The "<:" and ">:" operators
brackets are also used for specialization. The ``<:`` and ``>:`` operators
are used to specify upper and lower bounds, respectively.
Scala uses use-site variance but also allows declaration-site variance
specification. It uses a "+" or "-" prefix operator for covariance and
specification. It uses a ``+`` or ``-`` prefix operator for covariance and
contravariance, respectively.
Scala provides no way to specify a default type argument.
@ -1003,7 +1009,7 @@ Scala provides no way to specify a default type argument.
It does support higher-kinded types (type parameters that accept type
type parameters).
::
.. code-block:: scala
// Generic class; type parameter has upper bound
@ -1036,17 +1042,16 @@ Swift
Swift uses angle brackets to declare type parameters and for specialization.
The upper bound of a type parameter is specified using a colon.
Swift uses declaration-site variance, and variance of type parameters is
inferred from their usage.
Swift doesn't support generic variance; all type parameters are invariant.
Swift provides no way to specify a default type argument.
::
.. code-block:: swift
// Generic class
class ClassA<T> {
// Generic method
func method1<X>(val: T) -> S { }
func method1<X>(val: T) -> X { }
}
// Type parameter with upper bound constraint
@ -1061,23 +1066,33 @@ Rust
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 "where" clause can specify various constraints.
a ``where`` clause can specify various constraints.
Rust uses declaration-site variance, and variance of type parameters is
typically inferred from their usage. In cases where a type parameter is not
used within a type, variance can be specified explicitly.
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.
A default type argument can be specified using the "=" operator.
A default type argument can be specified using the ``=`` operator.
::
.. code-block:: rust
// Generic class
struct StructA<T> {
struct StructA<T> { // T's lifetime is inferred as covariant
x: T
}
fn f<'a>(
mut short_lifetime: StructA<&'a i32>,
mut long_lifetime: StructA<&'static i32>,
) {
long_lifetime = short_lifetime;
// error: StructA<&'a i32> is not a subtype of StructA<&'static i32>
short_lifetime = long_lifetime;
// valid: StructA<&'static i32> is a subtype of StructA<&'a i32>
}
// Type parameter with bound
struct StructB<T: StructA> {}
struct StructB<T: SomeTrait> {}
// Type parameter with additional constraints
struct StructC<T>
@ -1089,56 +1104,55 @@ A default type argument can be specified using the "=" operator.
// Generic function
fn func1<T>(val: &[T]) -> T { }
// Explicit variance specification
use type_variance::{Covariant, Contravariant};
struct StructD<A, R> {
arg: Covariant<A>,
ret: Contravariant<R>,
}
// Generic type alias
type MyType<T> = StructC<T>
type MyType<T> = StructC<T>;
Kotlin
------
Kotlin uses angle brackets to declare type parameters and for specialization.
The upper bound of a type is specified using a colon.
By default, type parameters are invariant. The upper bound of a type is
specified using a colon.
Alternatively, a ``where`` clause can specify various constraints.
Kotlin supports declaration-site variance where variance of type parameters is
explicitly declared using "in" and "out" keywords. It also supports use-site
explicitly declared using ``in`` and ``out`` keywords. It also supports use-site
variance which limits which methods and members can be used.
Kotlin provides no way to specify a default type argument.
::
.. code-block:: kotlin
// Generic class
class ClassA<T> { }
class ClassA<T>
// Type parameter with upper bound
class ClassB<T: SomeClass1> { }
class ClassB<T : SomeClass1>
// Contravariant and covariant type parameters
class ClassC<in S, out T> { }
class ClassC<in S, out T>
// Generic function
fun func1<T>() -> T {}
fun <T> func1(): T {
// Use site variance
val covariantA: ClassA<out Number>
val contravariantA: ClassA<in Number>
}
// Generic type alias
typealias<T> = ClassA<T>
typealias TypeAliasFoo<T> = ClassA<T>
Julia
-----
Julia uses curly braces to declare type parameters and for specialization.
The "<:" operator can be used within a "where" clause to declare
The ``<:`` operator can be used within a ``where`` clause to declare
upper and lower bounds on a type.
::
.. code-block:: julia
// Generic struct; type parameter with upper and lower bounds
struct StructA{T} where Int <: T <: Number
@ -1151,6 +1165,62 @@ upper and lower bounds on a type.
// Alternate form of generic function
function func2(v::Container{T} where T <: Real)
Dart
----
Dart uses angle brackets to declare type parameters and for specialization.
The upper bound of a type is specified using the ``extends`` keyword.
By default, type parameters are covariant.
Dart supports declaration-site variance, where variance of type parameters is
explicitly declared using ``in``, ``out`` and ``inout`` keywords.
It does not support use-site variance.
Dart provides no way to specify a default type argument.
.. code-block:: dart
// Generic class
class ClassA<T> { }
// Type parameter with upper bound
class ClassB<T extends SomeClass1> { }
// Contravariant and covariant type parameters
class ClassC<in S, out T> { }
// Generic function
T func1<T>() { }
// Generic type alias
typedef TypeDefFoo<T> = ClassA<T>;
Go
--
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 ``any`` is used for an unbound type parameter.
Go doesn't support variance; all type parameters are invariant.
Go provides no way to specify a default type argument.
Go does not support generic type aliases.
.. code-block:: go
// Generic type without a bound
type TypeA[T any] struct {
t T
}
// Type parameter with upper bound
type TypeB[T SomeType1] struct { }
// Generic function
func func1[T any]() { }
Summary
-------
@ -1162,7 +1232,8 @@ Summary
| C++ | template | n/a | n/a | = | n/a | n/a |
| | <> | | | | | |
+------------+----------+---------+--------+----------+-----------+-----------+
| Java | <> | extends | | | use | inferred |
| Java | <> | extends | | | use | super, |
| | | | | | | extends |
+------------+----------+---------+--------+----------+-----------+-----------+
| C# | <> | where | | | decl | in, out |
+------------+----------+---------+--------+----------+-----------+-----------+
@ -1171,15 +1242,21 @@ Summary
+------------+----------+---------+--------+----------+-----------+-----------+
| Scala | [] | T <: X | T >: X | | use, decl | +, - |
+------------+----------+---------+--------+----------+-----------+-----------+
| Swift | <> | T: X | | | decl | inferred |
| Swift | <> | T: X | | | n/a | n/a |
+------------+----------+---------+--------+----------+-----------+-----------+
| Rust | <> | T: X, | | = | decl | inferred, |
| | | where | | | | explicit |
| Rust | <> | T: X, | | = | n/a | n/a |
| | | where | | | | |
+------------+----------+---------+--------+----------+-----------+-----------+
| Kotlin | <> | T: X | | | use, decl | inferred |
| Kotlin | <> | T: X, | | | use, decl | in, out |
| | | where | | | | |
+------------+----------+---------+--------+----------+-----------+-----------+
| Julia | {} | T <: X | X <: T | | n/a | n/a |
+------------+----------+---------+--------+----------+-----------+-----------+
| Dart | <> | extends | | | decl | in, out, |
| | | | | | | inout |
+------------+----------+---------+--------+----------+-----------+-----------+
| Go | [] | T X | | | n/a | n/a |
+------------+----------+---------+--------+----------+-----------+-----------+
| Python | [] | T: X | | | decl | inferred |
| (proposed) | | | | | | |
+------------+----------+---------+--------+----------+-----------+-----------+