or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdcompile-time.mdgeneric-programming.mdimmutable-arrays.mdindex.mdmacros.mdstructural-types.mdtuples.mdtype-safe-equality.md

tuples.mddocs/

0

# Tuples and Product Types

1

2

Scala 3 provides a rich tuple system supporting arbitrary arity, comprehensive type-level operations, and both traditional and named tuples for enhanced type safety and expressiveness.

3

4

## Core Tuple API

5

6

### Tuple Trait

7

8

```scala { .api }

9

sealed trait Tuple extends Product:

10

def toArray: Array[Object]

11

def toList: List[Union[this.type]]

12

def toIArray: IArray[Object]

13

def :*[L](x: L): This :* L

14

def *:[H](x: H): H *: This

15

def apply(n: Int): Elem[This, n.type]

16

def head: Head[This]

17

def tail: Tail[This]

18

def init: Init[This]

19

def last: Last[This]

20

def ++[T2 <: Tuple](that: Tuple): This ++ that.type

21

def size: Size[This]

22

def zip[T2 <: Tuple](t2: T2): Zip[This, T2]

23

def map[F[_]](f: [t] => t => F[t]): Map[this.type, F]

24

def take(n: Int): Take[This, n.type]

25

def drop(n: Int): Drop[This, n.type]

26

def splitAt(n: Int): Split[This, n.type]

27

def reverse: Reverse[This]

28

```

29

30

Base trait for all tuples providing rich manipulation operations.

31

32

### Tuple Construction Types

33

34

```scala { .api }

35

type EmptyTuple = EmptyTuple.type

36

case object EmptyTuple extends Tuple

37

38

sealed trait NonEmptyTuple extends Tuple

39

sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple

40

```

41

42

- **`EmptyTuple`**: The empty tuple `()`

43

- **`NonEmptyTuple`**: Base trait for non-empty tuples

44

- **`*:`**: Infix type constructor for building tuples (e.g., `String *: Int *: EmptyTuple`)

45

46

### Tuple Factory Methods

47

48

```scala { .api }

49

object Tuple:

50

def apply(): EmptyTuple

51

def apply[T](x: T): T *: EmptyTuple

52

def fromArray[T](xs: Array[T]): Tuple

53

def fromIArray[T](xs: IArray[T]): Tuple

54

def fromProduct(product: Product): Tuple

55

def fromProductTyped[P <: Product](p: P)(using m: Mirror.ProductOf[P]): m.MirroredElemTypes

56

```

57

58

Factory methods for creating tuples from various sources.

59

60

## Type-Level Operations

61

62

### Element Access Types

63

64

```scala { .api }

65

type Head[X <: Tuple] // First element type

66

type Tail[X <: Tuple] <: Tuple // All but first element

67

type Init[X <: Tuple] <: Tuple // All but last element

68

type Last[X <: Tuple] // Last element type

69

type Elem[X <: Tuple, N <: Int] // Element at index N

70

```

71

72

### Tuple Manipulation Types

73

74

```scala { .api }

75

type Append[X <: Tuple, Y] <: NonEmptyTuple

76

type :*[X <: Tuple, Y] = Append[X, Y] // Infix append

77

78

type Concat[X <: Tuple, +Y <: Tuple] <: Tuple

79

type ++[X <: Tuple, +Y <: Tuple] = Concat[X, Y] // Infix concat

80

81

type Size[X <: Tuple] <: Int

82

type Reverse[X <: Tuple] <: Tuple

83

84

type Take[T <: Tuple, N <: Int] <: Tuple

85

type Drop[T <: Tuple, N <: Int] <: Tuple

86

type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])

87

```

88

89

### Advanced Type Operations

90

91

```scala { .api }

92

type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple

93

type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple

94

type Filter[Tup <: Tuple, P[_ <: Union[Tup]] <: Boolean] <: Tuple

95

type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple

96

type Union[T <: Tuple] // Union of all element types

97

type Fold[Tup <: Tuple, Z, F[_, _]]

98

```

99

100

## Named Tuples

101

102

### NamedTuple Type

103

104

```scala { .api }

105

opaque type NamedTuple[N <: Tuple, +V <: Tuple] >: V <: AnyNamedTuple = V

106

opaque type AnyNamedTuple = Any

107

type Empty = NamedTuple[EmptyTuple, EmptyTuple]

108

```

109

110

Named tuples provide field names as part of the type, enabling type-safe field access.

111

112

### NamedTuple Factory Methods

113

114

```scala { .api }

115

object NamedTuple:

116

def apply[N <: Tuple, V <: Tuple](x: V): NamedTuple[N, V]

117

def build[N <: Tuple]()[V <: Tuple](x: V): NamedTuple[N, V]

118

val Empty: Empty

119

```

120

121

### NamedTuple Operations

122

123

```scala { .api }

124

extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]):

125

def toTuple: V

126

def apply(n: Int): Elem[NamedTuple[N, V], n.type]

127

def size: Size[NamedTuple[N, V]]

128

def head: Head[NamedTuple[N, V]]

129

def tail: Tail[NamedTuple[N, V]]

130

def last: Last[NamedTuple[N, V]]

131

def init: Init[NamedTuple[N, V]]

132

def take(n: Int): Take[NamedTuple[N, V], n.type]

133

def drop(n: Int): Drop[NamedTuple[N, V], n.type]

134

def ++[N2, V2](that: NamedTuple[N2, V2])(using Tuple.Disjoint[N, N2] =:= true): Concat[...]

135

def map[F[_]](f: [t] => t => F[t]): Map[NamedTuple[N, V], F]

136

def reverse: Reverse[NamedTuple[N, V]]

137

def zip[V2](that: NamedTuple[N, V2]): Zip[NamedTuple[N, V], NamedTuple[N, V2]]

138

```

139

140

### NamedTuple Type Operations

141

142

```scala { .api }

143

type Names[X <: AnyNamedTuple] <: Tuple // Extract field names

144

type DropNames[NT <: AnyNamedTuple] <: Tuple // Extract values

145

type From[T] <: AnyNamedTuple // Convert class fields to named tuple

146

```

147

148

## Usage Examples

149

150

### Basic Tuple Operations

151

152

```scala

153

// Creating tuples

154

val empty = EmptyTuple

155

val single = Tuple("hello")

156

val triple = ("Alice", 25, true)

157

158

// Accessing elements

159

val first = triple.head // "Alice"

160

val rest = triple.tail // (25, true)

161

val last = triple.last // true

162

val second = triple.apply(1) // 25

163

164

// Adding elements

165

val extended = triple :* "Engineer" // ("Alice", 25, true, "Engineer")

166

val prepended = "Dr." *: triple // ("Dr.", "Alice", 25, true)

167

168

// Tuple operations

169

val size = triple.size // 3

170

val reversed = triple.reverse // (true, 25, "Alice")

171

val firstTwo = triple.take(2) // ("Alice", 25)

172

val lastTwo = triple.drop(1) // (25, true)

173

```

174

175

### Type-Level Computations

176

177

```scala

178

import scala.compiletime.constValue

179

180

type MyTuple = String *: Int *: Boolean *: EmptyTuple

181

val size: 3 = constValue[Tuple.Size[MyTuple]]

182

type FirstElement = Tuple.Head[MyTuple] // String

183

type RestElements = Tuple.Tail[MyTuple] // Int *: Boolean *: EmptyTuple

184

```

185

186

### Named Tuples

187

188

```scala

189

// Creating named tuples with literal syntax

190

val person = (name = "Bob", age = 30, active = true)

191

192

// Type-safe field access

193

val name: String = person.name

194

val age: Int = person.age

195

196

// Operations preserve names

197

val reversed = person.reverse // (active = true, age = 30, name = "Bob")

198

val older = person.map([t] => (x: t) => x match

199

case age: Int => age + 1

200

case other => other

201

) // (name = "Bob", age = 31, active = true)

202

203

// Concatenation requires disjoint names

204

val address = (street = "Main St", city = "Boston")

205

val fullInfo = person ++ address

206

// (name = "Bob", age = 30, active = true, street = "Main St", city = "Boston")

207

```

208

209

### Generic Programming with Tuples

210

211

```scala

212

def processTuple[T <: Tuple](t: T): String =

213

t.toList.mkString(", ")

214

215

def tupleMap[T <: Tuple, F[_]](t: T)(f: [U] => U => F[U]): Tuple.Map[T, F] =

216

t.map(f)

217

218

// Usage

219

val data = ("hello", 42, true)

220

processTuple(data) // "hello, 42, true"

221

222

val lengths = tupleMap(("abc", "hello", "x"))([T] => (s: T) => s match

223

case str: String => str.length

224

case other => 0

225

) // (3, 5, 1)

226

```

227

228

### Pattern Matching

229

230

```scala

231

def analyzeTuple(t: Tuple): String = t match

232

case EmptyTuple => "empty"

233

case single *: EmptyTuple => s"single: $single"

234

case first *: second *: EmptyTuple => s"pair: $first, $second"

235

case head *: tail => s"multiple: $head and ${tail.size} more"

236

237

// With named tuples

238

def analyzeUser(user: AnyNamedTuple): String = user match

239

case person if person.toTuple.size == 3 => "Person with 3 fields"

240

case _ => "Other structure"

241

```

242

243

### Conversion Operations

244

245

```scala

246

val tuple = ("a", "b", "c")

247

248

// Convert to collections

249

val array = tuple.toArray // Array("a", "b", "c")

250

val list = tuple.toList // List("a", "b", "c")

251

val iarray = tuple.toIArray // IArray("a", "b", "c")

252

253

// From collections

254

val fromArray = Tuple.fromArray(Array(1, 2, 3))

255

val fromProduct = Tuple.fromProduct(("x", "y"))

256

```

257

258

### Advanced Type-Level Operations

259

260

```scala

261

// Filter tuple elements by type predicate

262

type IsString[X] <: Boolean = X match

263

case String => true

264

case _ => false

265

266

type MixedTuple = Int *: String *: Boolean *: String *: EmptyTuple

267

type StringsOnly = Tuple.Filter[MixedTuple, IsString] // String *: String *: EmptyTuple

268

269

// Map over tuple types

270

type ToOption[X] = Option[X]

271

type OptionTuple = Tuple.Map[MixedTuple, ToOption]

272

// Option[Int] *: Option[String] *: Option[Boolean] *: Option[String] *: EmptyTuple

273

274

// Fold tuple types

275

type StringConcat[X, Y] = (X, Y) match

276

case (String, String) => String

277

case _ => String

278

279

type AllStrings = String *: String *: String *: EmptyTuple

280

type ConcatResult = Tuple.Fold[AllStrings, String, StringConcat] // String

281

```

282

283

This comprehensive tuple system enables both runtime manipulation and compile-time type-level programming, making Scala 3 tuples extremely powerful for generic programming and type-safe data manipulation.