diff options
Diffstat (limited to 'spec/03-types.md')
-rw-r--r-- | spec/03-types.md | 133 |
1 files changed, 78 insertions, 55 deletions
diff --git a/spec/03-types.md b/spec/03-types.md index 94b7916634..a3167646ca 100644 --- a/spec/03-types.md +++ b/spec/03-types.md @@ -105,7 +105,7 @@ forms. SimpleType ::= Path ‘.’ type ``` -A singleton type is of the form $p.$`type`, where $p$ is a +A _singleton type_ is of the form $p.$`type`, where $p$ is a path pointing to a value expected to [conform](06-expressions.html#expression-typing) to `scala.AnyRef`. The type denotes the set of values consisting of `null` and the value denoted by $p$. @@ -119,7 +119,7 @@ declared to be a subtype of trait `scala.Singleton`. SimpleType ::= SimpleType ‘#’ id ``` -A type projection $T$#$x$ references the type member named +A _type projection_ $T$#$x$ references the type member named $x$ of type $T$. <!-- @@ -134,7 +134,7 @@ If $x$ references an abstract type member, then $T$ must be a SimpleType ::= StableId ``` -A type designator refers to a named value type. It can be simple or +A _type designator_ refers to a named value type. It can be simple or qualified. All such type designators are shorthands for type projections. Specifically, the unqualified type name $t$ where $t$ is bound in some @@ -167,7 +167,7 @@ SimpleType ::= SimpleType TypeArgs TypeArgs ::= ‘[’ Types ‘]’ ``` -A parameterized type $T[ T_1 , \ldots , T_n ]$ consists of a type +A _parameterized type_ $T[ T_1 , \ldots , T_n ]$ consists of a type designator $T$ and type parameters $T_1 , \ldots , T_n$ where $n \geq 1$. $T$ must refer to a type constructor which takes $n$ type parameters $a_1 , \ldots , a_n$. @@ -227,7 +227,7 @@ G[S, Int] // illegal: S constrains its parameter to SimpleType ::= ‘(’ Types ‘)’ ``` -A tuple type $(T_1 , \ldots , T_n)$ is an alias for the +A _tuple type_ $(T_1 , \ldots , T_n)$ is an alias for the class `scala.Tuple$n$[$T_1$, … , $T_n$]`, where $n \geq 2$. Tuple classes are case classes whose fields can be accessed using @@ -255,7 +255,7 @@ trait Product_n[+$T_1$, … , +$T_n$] { AnnotType ::= SimpleType {Annotation} ``` -An annotated type $T$ $a_1, \ldots, a_n$ +An _annotated type_ $T$ $a_1, \ldots, a_n$ attaches [annotations](11-annotations.html#user-defined-annotations) $a_1 , \ldots , a_n$ to the type $T$. @@ -278,7 +278,7 @@ RefineStat ::= Dcl | ``` -A compound type $T_1$ `with` … `with` $T_n \\{ R \\}$ +A _compound type_ $T_1$ `with` … `with` $T_n \\{ R \\}$ represents objects with members as given in the component types $T_1 , \ldots , T_n$ and the refinement $\\{ R \\}$. A refinement $\\{ R \\}$ contains declarations and type definitions. @@ -343,7 +343,7 @@ a value `callsign` and a `fly` method. InfixType ::= CompoundType {id [nl] CompoundType} ``` -An infix type $T_1$ `op` $T_2$ consists of an infix +An _infix type_ $T_1$ `op` $T_2$ consists of an infix operator `op` which gets applied to two type operands $T_1$ and $T_2$. The type is equivalent to the type application `op`$[T_1, T_2]$. The infix operator `op` may be an @@ -410,7 +410,7 @@ ExistentialDcl ::= ‘type’ TypeDcl | ‘val’ ValDcl ``` -An existential type has the form `$T$ forSome { $Q$ }` +An _existential type_ has the form `$T$ forSome { $Q$ }` where $Q$ is a sequence of [type declarations](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases). @@ -507,7 +507,7 @@ Assume the class definitions ```scala class Ref[T] -abstract class Outer { type T } . +abstract class Outer { type T } ``` Here are some examples of existential types: @@ -530,7 +530,7 @@ Ref[_ <: java.lang.Number] The type `List[List[_]]` is equivalent to the existential type ```scala -List[List[t] forSome { type t }] . +List[List[t] forSome { type t }] ``` ###### Example @@ -564,7 +564,7 @@ report as the internal types of defined identifiers. ### Method Types -A method type is denoted internally as $(\mathit{Ps})U$, where $(\mathit{Ps})$ +A _method type_ is denoted internally as $(\mathit{Ps})U$, where $(\mathit{Ps})$ is a sequence of parameter names and types $(p_1:T_1 , \ldots , p_n:T_n)$ for some $n \geq 0$ and $U$ is a (value or method) type. This type represents named methods that take arguments named $p_1 , \ldots , p_n$ @@ -587,7 +587,7 @@ corresponding function type. The declarations -``` +```scala def a: Int def b (x: Int): Boolean def c (x: Int) (y: String, z: String): String @@ -631,7 +631,7 @@ union : [A >: Nothing <: Comparable[A]] (x: Set[A], xs: Set[A]) Set[A] ### Type Constructors -A type constructor is represented internally much like a polymorphic method type. +A _type constructor_ is represented internally much like a polymorphic method type. `[$\pm$ $a_1$ >: $L_1$ <: $U_1 , \ldots , \pm a_n$ >: $L_n$ <: $U_n$] $T$` represents a type that is expected by a [type constructor parameter](04-basic-declarations-and-definitions.html#type-parameters) or an @@ -642,7 +642,7 @@ the corresponding type parameter clause. Consider this fragment of the `Iterable[+X]` class: -``` +```scala trait Iterable[+X] { def flatMap[newType[+X] <: Iterable[X], S](f: X => newType[S]): newType[S] } @@ -660,7 +660,7 @@ same name, we model An overloaded type consisting of type alternatives $T_1 \commadots T_n (n \geq 2)$ is denoted internally $T_1 \overload \ldots \overload T_n$. ###### Example -``` +```scala def println: Unit def println(s: String): Unit = $\ldots$ def println(x: Float): Unit = $\ldots$ @@ -678,7 +678,7 @@ println: => Unit $\overload$ ``` ###### Example -``` +```scala def f(x: T): T = $\ldots$ val f = 0 ``` @@ -778,25 +778,22 @@ These notions are defined mutually recursively as follows. ## Relations between types -We define two relations between types. +We define the following relations between types. -|Name | Symbolically |Interpretation | -|-----------------|----------------|-------------------------------------------------| -|Equivalence |$T \equiv U$ |$T$ and $U$ are interchangeable in all contexts. | -|Conformance |$T <: U$ |Type $T$ conforms to type $U$. | +| Name | Symbolically | Interpretation | +|------------------|----------------|----------------------------------------------------| +| Equivalence | $T \equiv U$ | $T$ and $U$ are interchangeable in all contexts. | +| Conformance | $T <: U$ | Type $T$ conforms to ("is a subtype of") type $U$. | +| Weak Conformance | $T <:_w U$ | Augments conformance for primitive numeric types. | +| Compatibility | | Type $T$ conforms to type $U$ after conversions. | ### Equivalence -Equivalence $(\equiv)$ between types is the smallest congruence [^congruence] such that -the following holds: +Equivalence $(\equiv)$ between types is the smallest congruence [^congruence] such that the following holds: -- If $t$ is defined by a type alias `type $t$ = $T$`, then $t$ is - equivalent to $T$. -- If a path $p$ has a singleton type `$q$.type`, then - `$p$.type $\equiv q$.type`. -- If $O$ is defined by an object definition, and $p$ is a path - consisting only of package or object selectors and ending in $O$, then - `$O$.this.type $\equiv p$.type`. +- If $t$ is defined by a type alias `type $t$ = $T$`, then $t$ is equivalent to $T$. +- If a path $p$ has a singleton type `$q$.type`, then `$p$.type $\equiv q$.type`. +- If $O$ is defined by an object definition, and $p$ is a path consisting only of package or object selectors and ending in $O$, then `$O$.this.type $\equiv p$.type`. - Two [compound types](#compound-types) are equivalent if the sequences of their component are pairwise equivalent, and occur in the same order, and their refinements are equivalent. Two refinements are equivalent if they @@ -827,14 +824,11 @@ the following holds: ### Conformance -The conformance relation $(<:)$ is the smallest -transitive relation that satisfies the following conditions. +The conformance relation $(<:)$ is the smallest transitive relation that satisfies the following conditions. - Conformance includes equivalence. If $T \equiv U$ then $T <: U$. - For every value type $T$, `scala.Nothing <: $T$ <: scala.Any`. -- For every type constructor $T$ (with any number of type parameters), - `scala.Nothing <: $T$ <: scala.Any`. - +- For every type constructor $T$ (with any number of type parameters), `scala.Nothing <: $T$ <: scala.Any`. - For every class type $T$ such that `$T$ <: scala.AnyRef` one has `scala.Null <: $T$`. - A type variable or abstract type $t$ conforms to its upper bound and its lower bound conforms to $t$. @@ -912,15 +906,12 @@ type $C'$, if one of the following holds. type declaration `type t[$T_1$ , … , $T_n$] >: L <: U` if $L <: t <: U$. -The $(<:)$ relation forms pre-order between types, -i.e. it is transitive and reflexive. _least upper bounds_ and -_greatest lower bounds_ of a set of types -are understood to be relative to that order. -###### Note -The least upper bound or greatest lower bound -of a set of types does not always exist. For instance, consider -the class definitions +#### Least upper bounds and greatest lower bounds +The $(<:)$ relation forms pre-order between types, i.e. it is transitive and reflexive. +This allows us to define _least upper bounds_ and _greatest lower bounds_ of a set of types in terms of that order. +The least upper bound or greatest lower bound of a set of types does not always exist. +For instance, consider the class definitions: ```scala class A[+T] {} @@ -949,11 +940,9 @@ free to pick any one of them. ### Weak Conformance -In some situations Scala uses a more general conformance relation. A -type $S$ _weakly conforms_ -to a type $T$, written $S <:_w -T$, if $S <: T$ or both $S$ and $T$ are primitive number types -and $S$ precedes $T$ in the following ordering. +In some situations Scala uses a more general conformance relation. +A type $S$ _weakly conforms_ to a type $T$, written $S <:_w T$, +if $S <: T$ or both $S$ and $T$ are primitive number types and $S$ precedes $T$ in the following ordering. ```scala Byte $<:_w$ Short @@ -964,15 +953,49 @@ Long $<:_w$ Float Float $<:_w$ Double ``` -A _weak least upper bound_ is a least upper bound with respect to -weak conformance. +A _weak least upper bound_ is a least upper bound with respect to weak conformance. + +### Compatibility +A type $T$ is _compatible_ to a type $U$ if $T$ (or its corresponding function type) [weakly conforms](#weak-conformance) to $U$ +after applying [eta-expansion](06-expressions.html#eta-expansion). If $T$ is a method type, it's converted to the corresponding function type. If the types do not weakly conform, the following alternatives are checked in order: + - [view application](07-implicits.html#views): there's an implicit view from $T$ to $U$; + - dropping by-name modifiers: if $U$ is of the shape `$=> U'$` (and $T$ is not), `$T <:_w U'$`; + - SAM conversion: if $T$ corresponds to a function type, and $U$ declares a single abstract method whose type [corresponds](06-expressions.html#sam-conversion) to the function type $U'$, `$T <:_w U'$`. + +<!--- TODO: include other implicit conversions in addition to view application? + + trait Proc { def go(x: Any): Unit } + + def foo(x: Any => Unit): Unit = ??? + def foo(x: Proc): Unit = ??? + + foo((x: Any) => 1) // works when you drop either foo overload since value discarding is applied + +--> + +#### Examples + +##### Function compatibility via SAM conversion + +Given the definitions + +```scala +def foo(x: Int => String): Unit +def foo(x: ToString): Unit + +trait ToString { def convert(x: Int): String } +``` + +The application `foo((x: Int) => x.toString)` [resolves](06-expressions.html#overloading-resolution) to the first overload, +as it's more specific: + - `Int => String` is compatible to `ToString` -- when expecting a value of type `ToString`, you may pass a function literal from `Int` to `String`, as it will be SAM-converted to said function; + - `ToString` is not compatible to `Int => String` -- when expecting a function from `Int` to `String`, you may not pass a `ToString`. ## Volatile Types -Type volatility approximates the possibility that a type parameter or abstract -type instance -of a type does not have any non-null values. A value member of a volatile type -cannot appear in a [path](#paths). +Type volatility approximates the possibility that a type parameter or +abstract type instance of a type does not have any non-null values. +A value member of a volatile type cannot appear in a [path](#paths). A type is _volatile_ if it falls into one of four categories: |