-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
PEP 695: Fix/improve syntax & content of Language Survey section #2725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
af25340
047483f
061f90b
a7b84dd
2fbe588
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,39 +896,44 @@ 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 | ||
not specified explicitly. | ||
|
||
Java provides no way to specify a default type argument. | ||
|
||
:: | ||
.. code-block:: java | ||
|
||
// Generic class | ||
public class ClassA<T> { | ||
public Container<T> t; | ||
|
||
// Generic method | ||
public <S extends Number> void method1(S value) { } | ||
|
||
// Use site variance | ||
public void method1(ClassA<? super Integer> value) { } | ||
} | ||
|
||
|
||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Readability was not the motivation for adding this capability. I meet often with the TypeScript team, and I'm very familiar with their motivations and the debates that led to their (reluctant) decision to add this capability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It wasn't a motivation, but my edit here was based on information from the documentation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide some references for these reasons? Reading the pr microsoft/TypeScript#48240, it seems to lead with positive motivations and nothing negative that I can see:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This information comes from direct conversations with Anders Hejlsberg, Ryan Cavanaugh, and Daniel Rosenwasser, the leads on the TypeScript team. I've discussed the arguments you've raised about variance. Here's how Daniel summarized their advice: |
||
|
||
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,19 +997,19 @@ 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. | ||
|
||
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) | | | | | | | | ||
+------------+----------+---------+--------+----------+-----------+-----------+ | ||
|
Uh oh!
There was an error while loading. Please reload this page.