From 754c8fb1f6a17695c554158140c11365692b90e3 Mon Sep 17 00:00:00 2001 From: KotlinIsland <65446343+KotlinIsland@users.noreply.github.com> Date: Mon, 29 Aug 2022 03:00:56 +1000 Subject: [PATCH] PEP 695: Fix/improve syntax & content of Language Survey section (#2725) --- pep-0695.rst | 191 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 134 insertions(+), 57 deletions(-) diff --git a/pep-0695.rst b/pep-0695.rst index 481a3ccef..ea3348ee5 100644 --- a/pep-0695.rst +++ b/pep-0695.rst @@ -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 @@ -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 { @@ -912,6 +914,9 @@ Java provides no way to specify a default type argument. // Generic method public void method1(S value) { } + + // Use site variance + public void method1(ClassA 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 @@ -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 { @@ -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 { // Generic method - func method1(val: T) -> S { } + func method1(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 { + struct StructA { // 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 {} + struct StructB {} // Type parameter with additional constraints struct StructC @@ -1089,56 +1104,55 @@ A default type argument can be specified using the "=" operator. // Generic function fn func1(val: &[T]) -> T { } - // Explicit variance specification - use type_variance::{Covariant, Contravariant}; - - struct StructD { - arg: Covariant, - ret: Contravariant, - } - // Generic type alias - type MyType = StructC + type MyType = StructC; 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 { } + class ClassA // Type parameter with upper bound - class ClassB { } + class ClassB // Contravariant and covariant type parameters - class ClassC { } + class ClassC // Generic function - fun func1() -> T {} + fun func1(): T { + + // Use site variance + val covariantA: ClassA + val contravariantA: ClassA + } // Generic type alias - typealias = ClassA + typealias TypeAliasFoo = ClassA 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 { } + + // Type parameter with upper bound + class ClassB { } + + // Contravariant and covariant type parameters + class ClassC { } + + // Generic function + T func1() { } + + // Generic type alias + typedef TypeDefFoo = ClassA; + +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) | | | | | | | +------------+----------+---------+--------+----------+-----------+-----------+