Skip to content

Commit 4480e9c

Browse files
committed
Add doc page
1 parent 1e5b35a commit 4480e9c

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
layout: doc-page
3+
title: "Named Tuples"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/named-tuples.html
5+
---
6+
7+
The elements of a tuple can now be named. Example:
8+
```scala
9+
type Person = (name: String, age: Int)
10+
val Bob: Person = (name = "Bob", age = 33)
11+
12+
Bob match
13+
case (name, age) =>
14+
println(s"$name is $age years old")
15+
16+
val persons: List[Person] = ...
17+
val minors = persons.filter: p =>
18+
p.age < 18
19+
```
20+
Named bindings in tuples are similar to function parameters and arguments. We use `name: Type` for element types and `name = value` for element values. It is illegal to mix named and unnamed elements in a tuple, or to use the same same
21+
name for two different elements.
22+
23+
Fields of named tuples can be selected by their name, as in the line `p.age < 18` above.
24+
25+
### Conformance
26+
27+
The order of names in a named tuple matters. For instance, the type `Person` above and the type `(age: Int, name: String)` would be different, incompatible types.
28+
29+
Values of named tuple types can also be be defined using regular tuples. For instance:
30+
```scala
31+
val x: Person = ("Laura", 25)
32+
33+
def register(person: Person) = ...
34+
register(person = ("Silvain", 16))
35+
register(("Silvain", 16))
36+
```
37+
This follows since a regular tuple `(T_1, ..., T_n)` is treated as a subtype of a named tuple `(N_1 = T_1, ..., N_n = T_n)` with the same element types. On the other hand, named tuples do not conform to unnamed tuples, so the following is an error:
38+
```scala
39+
val x: (String, Int) = Bob // error: type mismatch
40+
```
41+
One can convert a named tuple to an unnamed tuple with the `dropNames` method, so the following works:
42+
```scala
43+
val x: (String, Int) = Bob.dropNames // ok
44+
```
45+
Note that conformance rules for named tuples are analogous to the rules for named parameters. One can assign parameters by position to a named parameter list.
46+
```scala
47+
def f(param: Int) = ...
48+
f(param = 1) // OK
49+
f(2) // Also OK
50+
```
51+
But one cannot use a name to pass an argument to an unnamed parameter:
52+
```scala
53+
val f: Int => T
54+
f(2) // OK
55+
f(param = 2) // Not OK
56+
```
57+
The rules for tuples are analogous. Unnamed tuples conform to named tuple types, but the opposite does not hold.
58+
59+
60+
### Pattern Matching
61+
62+
When pattern matching on a named tuple, the pattern may be named or unnamed.
63+
If the pattern is named it needs to mention only a subset of the tuple names, and these names can come in any order. So the following are all OK:
64+
```scala
65+
Bob match
66+
case (name, age) => ...
67+
68+
Bob match
69+
case (name = x, age = y) => ...
70+
71+
Bob match
72+
case (age = x) => ...
73+
74+
Bob match
75+
case (age = x, name = y) => ...
76+
```
77+
78+
### Expansion
79+
80+
Named tuples are in essence just a convenient syntax for regular tuples. In the internal representation, a named tuple type is represented at compile time as a pair of two tuples. One tuple contains the names as literal constant string types, the other contains the element types. The runtime representation of a named tuples consists of just the element values, whereas the names are forgotten. This is achieved by declaring `NamedTuple`
81+
in package `scala` as an opaque type as follows:
82+
```scala
83+
opaque type NamedTuple[N <: Tuple, +V <: Tuple] >: V = V
84+
```
85+
For instance, the `Person` type would be represented as the type
86+
```scala
87+
NamedTuple[("name", "age"), (String, Int)]
88+
```
89+
`NamedTuple` is an opaque type alias of its second, value parameter. The first parameter is a string constant type which determines the name of the element. Since the type is just an alias of its value part, names are erased at runtime, and named tuples and regular tuples have the same representation.
90+
91+
A `NamedTuple[N, V]` type is publicly known to be a supertype (but not a subtype) of its value paramater `V`, which means that regular tuples can be assigned to named tuples but not _vice versa_.
92+
93+
The `NamedTuple` object contains a number of extension methods for named tuples hat mirror the same functions in `Tuple`. Examples are
94+
`apply`, `head`, `tail`, `take`, `drop`, `++`, `map`, or `zip`.
95+
Similar to `Tuple`, the `NamedTuple` object also contains types such as `Elem`, `Head`, `Concat`
96+
that describe the results of these extension methods.
97+
98+
The translation of named tuples to instances of `NamedTuple` is fixed by the specification and therefore known to the programmer. This means that:
99+
100+
- All tuple operations also work with named tuples "out of the box".
101+
- Macro libraries can rely on this expansion.
102+
103+
### Restrictions
104+
105+
The following restrictions apply to named tuple elements:
106+
107+
1. Either all elements of a tuple are named or none are named. It is illegal to mix named and unnamed elements in a tuple. For instance, the following is in error:
108+
```scala
109+
val illFormed1 = ("Bob", age = 33) // error
110+
```
111+
2. Each element name in a named tuple must be unique. For instance, the following is in error:
112+
```scala
113+
val illFormed2 = (name = "", age = 0, name = true) // error
114+
```
115+
3. Named tuples can be matched with either named or regular patterns. But regular tuples and other selector types can only be matched with regular tuple patterns. For instance, the following is in error:
116+
```scala
117+
(tuple: Tuple) match
118+
case (age = x) => // error
119+
```
120+
121+
### Syntax
122+
123+
The syntax of Scala is extended as follows to support named tuples:
124+
```
125+
SimpleType ::= ...
126+
| ‘(’ NameAndType {‘,’ NameAndType} ‘)’
127+
NameAndType ::= id ':' Type
128+
129+
SimpleExpr ::= ...
130+
| '(' NamedExprInParens {‘,’ NamedExprInParens} ')'
131+
NamedExprInParens ::= id '=' ExprInParens
132+
133+
SimplePattern ::= ...
134+
| '(' NamedPattern {‘,’ NamedPattern} ')'
135+
NamedPattern ::= id '=' Pattern
136+
```

0 commit comments

Comments
 (0)