Skip to content

Backport "Spec: Revisit Tuples and Function types." to LTS #19036

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

Merged
merged 1 commit into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions docs/_spec/03-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ In a sequence of consecutive type infix operations ´t_0 \, \mathit{op} \, t_1 \
If they are all left-associative, the sequence is interpreted as ´(... (t_0 \mathit{op_1} t_1) \mathit{op_2} ...) \mathit{op_n} t_n´, otherwise it is interpreted as ´t_0 \mathit{op_1} (t_1 \mathit{op_2} ( ... \mathit{op_n} t_n) ...)´.

The type operators `|` and `&` are not really special.
Nevertheless, unless shadowed, they resolve to `scala.|` and `scala.&`, which represent [union and intersection types](#union-and-intersection-types), respectively.
Nevertheless, unless shadowed, they resolve to [the fundamental type aliases `scala.|` and `scala.&`](./12-the-scala-standard-library.html#fundamental-type-aliases), which represent [union and intersection types](#union-and-intersection-types), respectively.

### Function Types

Expand Down Expand Up @@ -230,6 +230,21 @@ scala.PolyFunction {
}
```

### Tuple Types

```ebnf
SimpleType1 ::= ...
| ‘(’ TypesOrWildcards ‘)’
```

A _tuple type_ ´(T_1, ..., T_n)´ where ´n \geq 2´ is sugar for the type `´T_1´ *: ... *: ´T_n´ *: scala.EmptyTuple`, which is itself a series of nested infix types which are sugar for `*:[´T_1´, *:[´T_2´, ... *[´T_n´, scala.EmptyTuple]]]`.
The ´T_i´ can be wildcard type arguments.

Notes:

- `(´T_1´)` is the type ´T_1´, and not `´T_1´ *: scala.EmptyTuple` (´T_1´ cannot be a wildcard type argument in that case).
- `()` is not a valid type (not even `scala.EmptyTuple`).

### Concrete Refined Types

```ebnf
Expand Down Expand Up @@ -285,7 +300,7 @@ _Types_ are either _proper types_, _type constructors_ or _poly-kinded types_.

All types live in a single lattice with respect to a [_conformance_](#conformance) relationship ´<:´.
The _top type_ is `AnyKind` and the _bottom type_ is `Nothing`: all types conform to `AnyKind`, and `Nothing` conforms to all types.
They can be referred to as the standard library entities `scala.AnyKind` and `scala.Nothing`, respectively.
They can be referred to with [the fundamental type aliases `scala.AnyKind` and `scala.Nothing`](./12-the-scala-standard-library.html#fundamental-type-aliases), respectively.

Types can be _concrete_ or _abstract_.
An abstract type ´T´ always has lower and upper bounds ´L´ and ´H´ such that ´L >: T´ and ´T <: H´.
Expand Down Expand Up @@ -1086,7 +1101,7 @@ Note that the conditions are not all mutually exclusive.
- ´S_i´ and ´T_i´ are types and ´S_i =:= T_i´, or
- ´S_i´ is a type and ´T_i´ is a wildcard type argument of the form ´? >: L_2 <: H_2´ and ´L_2 <: S_i´ and ´S_i <: H_2´, or
- ´S_i´ is a wildcard type argument of the form ´? >: L_1 <: H_1´ and ´T_i´ is a wildcard type argument of the form ´? >: L_2 <: H_2´ and ´L_2 <: L_1´ and ´H_1 <: H_2´ (i.e., the ´S_i´ "interval" is contained in the ´T_i´ "interval").
- ´T = q.C[T_1, ..., T_n]´ with ´n \geq 0´ and `baseType(´S´, ´C´)` is defined and `baseType(´S´, ´C´) ´<: T´.
- ´T = q.C[T_1, ..., T_n]´ with ´n \geq 0´ and `baseType(´S´, ´C´)` is defined and `baseType(´S´, ´C´) ´<: T´`.
- ´S = p.X[S_1, ..., S_n]´ and ´p.X´ is non-class type designator and ´H <: T´ where ´H´ is the upper bound of the underlying type definition of ´p.X´.
- ´S = p.C´ and `´T = C´.this` and ´C´ is the hidden class of an `object` and:
- ´p = \epsilon´ or ´p´ is a package ref, or
Expand Down Expand Up @@ -1129,6 +1144,7 @@ Note that the conditions are not all mutually exclusive.
- ´S´ is a stable type and ´T = q.x´ is a term designator with underlying type ´T_1´ and ´T_1´ is a stable type and ´S <: T_1´.
- `´S = S_1´ { ´R´ }` and ´S_1 <: T´.
- `´S =´ { ´\alpha´ => ´S_1´ }` and ´S_1 <: T´.
- `´T =´ scala.Tuple´_n[T_1, ..., T_n]´` with ´1 \leq n \leq 22´, and `´S <: T_1´ *: ... *: ´T_n´ *: scala.EmptyTuple`.

We define `isSubPrefix(´p´, ´q´)` where ´p´ and ´q´ are prefixes as:

Expand Down
96 changes: 64 additions & 32 deletions docs/_spec/12-the-scala-standard-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,23 @@ Some of these classes are described in the following.
![Class hierarchy of Scala](public/images/classhierarchy.png)

<!-- TODO: Briefly mention scala.deprecated somewhere, and link to [deprecated page](./A%3F-deprecated.md) -->

## Fundamental Type Aliases

The `scala` package provides the following fundamental type aliases, which expose to user code some forms of [types](./03-types.html) that cannot otherwise be written:

```scala
type AnyKind = ´x´ // where ´x´ is the internal AnyKind type
type Nothing = ´x´ // where ´x´ is the internal Nothing type
type | = [A, B] =>> A ´|´ B // where | is the internal union type operator
type & = [A, B] =>> A ´&´ B // where & is the internal intersection type operator
```

## Root Classes

The root of this hierarchy is formed by class `Any`.
The root of this hierarchy is formed by class `scala.Any`.
Every class in a Scala execution environment inherits directly or indirectly from this class.
By definition, `Any` is also the top [proper type](./03-types.html#proper-types).
Class `Any` has two direct subclasses: `AnyRef` and `AnyVal`.

The subclass `AnyRef` represents all values which are represented as objects in the underlying host system.
Expand Down Expand Up @@ -304,42 +317,42 @@ case class Tuple´n´[+T_1, ..., +T_n](_1: T_1, ..., _´n´: T_´n´) {
-->
### The `Function` Classes

For each class type `Function´n´` where ´n = 0, ..., 22´, Scala defines the following function class:
For each natural ´n \geq 0´, the `scala` package defines the following function class:

```scala
package scala
trait Function´_n´[-´T_1´, ..., -´T_n´, +´R´]:
def apply(´x_1´: ´T_1´, ..., ´x_n´: ´T_n´): ´R´
override def toString = "<function´_n´>"
def curried: ´T_1´ => ... => ´T_n´ => R = ...
def tupled: ((´T_1´, ..., ´T_n´)) => R = ...
```

For function types `Function´n´` where ´n > 22´, Scala defines a unique function class:
These classes participate in the desugaring of [concrete function types](./03-types.html#function-types).

For values of ´n \leq 22´, the `Function´_n´` classes define additional methods:
```scala
package scala
trait FunctionXXL:
def apply(xs: IArray[Object]): Object
override def toString = "<functionXXL>"
trait Function´_n´[-´T_1´, ..., -´T_n´, +´R´]:
...
override def toString = "<function´_n´>"
def curried: ´T_1´ => ... => ´T_n´ => R = ...
def tupled: ((´T_1´, ..., ´T_n´)) => R = ...
```

There is no loss of type safety, as the internal representation is still `Function´n´` for all ´n´.
However this means methods `curried` and `tupled` are not available on functions with more than 22 parameters.

The implicitly imported [`Predef`](#the-predef-object) object defines the name
`Function` as an alias of `Function1`.

<!-- TODO: Remove below ? -->
The `PartialFunction` subclass of `Function1` represents functions that (indirectly) specify their domain.
Use the `isDefined` method to query whether the partial function is defined for a given input (i.e., whether the input is part of the function's domain).

```scala
class PartialFunction[-A, +B] extends Function1[A, B] {
def isDefinedAt(x: A): Boolean

... // various derived methods
}
```

`PartialFunction` participates in the desugaring of [pattern matching anonymous functions](08-pattern-matching.html#pattern-matching-anonymous-functions).

### Trait `Product`
<!-- TODO: Move somewhere else ? -->
<!-- TODO: Could not find more info on which non-Product methods case class automatically define -->
Expand All @@ -351,36 +364,55 @@ All enum definitions automatically extend the `reflect.Enum` trait (and generate

### Tuple Classes

Tuple classes are case classes whose fields can be accessed using selectors `_1`, ..., `_n`.
Their functionality is abstracted in the corresponding `scala.Product_´n´` trait.
The _n_-ary tuple class and product trait are defined at least as follows in the standard Scala library (they might also add other methods and implement other traits).
Tuples are a form of _HLists_ defined by the following classes:

```scala
case class Tuple´_n´[+´T_1´, ..., +´T_n´](_1: ´T_1´, ..., _n: ´T_n´)
extends Product´_n´[´T_1´, ..., ´T_n´]
/** Superclass of all tuples. */
sealed trait Tuple extends Product:
/** Return a new tuple by prepending the element to `this` tuple. */
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This = ...
...

trait Product´_n´[+´T_1´, ..., +´T_n´] extends Product:
override def productArity = ´n´
def _1: ´T_1´
object Tuple:
/** Type of the element at position N in the tuple X. */
type Elem[X <: Tuple, N <: Int] = ...
...
def _n: ´T_n´
```

#### Short-hand syntax
/** A tuple of 0 elements. */
type EmptyTuple = EmptyTuple.type

/** A tuple of 0 elements. */
case object EmptyTuple extends Tuple:
override def toString(): String = "()"

/** Tuple of arbitrary non-zero arity */
sealed trait NonEmptyTuple extends Tuple:
/** Get the i-th element of this tuple. */
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] = ...
...

Tuple classes have dedicated syntax.
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple

```ebnf
SimpleType ::= ‘(’ Types ‘)’
object `*:` :
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
```

A _tuple type_ ´(T_1, ..., T_n)´ where ´n \geq 2´ is an alias for the type `´T_1´ *: ... *: ´T_n´ *: scala.EmptyTuple`.
For ´1 \leq n \leq 22´, the concrete implementations of `*:` are instances of `Tuple´_n´` classes, which also implement corresponding `Product´_n´` traits.
They are defined at least as follows in the standard Scala library (they might also add other methods and implement other traits).

```scala
trait Product´_n´[+´T_1´, ..., +´T_n´] extends Product:
override def productArity: Int = ´n´
def _1: ´T_1´
...
def _n: ´T_n´

Notes:
- `(´T´)` is just the type ´T´, and not `´T´ *: scala.EmptyTuple`.
- `()` is not a valid type, and not `scala.EmptyTuple`.
final case class Tuple´_n´[+´T_1´, ..., +´T_n´](_1: ´T_1´, ..., _n: ´T_n´)
extends *:[´T_1´, ´T_2´ *: ... _: ´T_n´ *: EmptyTuple]
with Product´_n´[´T_1´, ..., ´T_n´]
```

If ´n \leq 22´, the type `´T_1´ *: ... *: ´T_n´ *: scala.EmptyTuple` is both a subtype and a supertype of tuple class `scala.Tuple´_n´[´T_1´, ..., ´T_n´]`.
For ´n > 22´, the concrete implementations of ´*:´ are instances of implementation-specific private classes.

### Class `Array`

Expand Down