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.
sealed trait Tuple extends Product:
def toArray: Array[Object]
def toList: List[Union[this.type]]
def toIArray: IArray[Object]
def :*[L](x: L): This :* L
def *:[H](x: H): H *: This
def apply(n: Int): Elem[This, n.type]
def head: Head[This]
def tail: Tail[This]
def init: Init[This]
def last: Last[This]
def ++[T2 <: Tuple](that: Tuple): This ++ that.type
def size: Size[This]
def zip[T2 <: Tuple](t2: T2): Zip[This, T2]
def map[F[_]](f: [t] => t => F[t]): Map[this.type, F]
def take(n: Int): Take[This, n.type]
def drop(n: Int): Drop[This, n.type]
def splitAt(n: Int): Split[This, n.type]
def reverse: Reverse[This]Base trait for all tuples providing rich manipulation operations.
type EmptyTuple = EmptyTuple.type
case object EmptyTuple extends Tuple
sealed trait NonEmptyTuple extends Tuple
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTupleEmptyTuple: The empty tuple ()NonEmptyTuple: Base trait for non-empty tuples*:: Infix type constructor for building tuples (e.g., String *: Int *: EmptyTuple)object Tuple:
def apply(): EmptyTuple
def apply[T](x: T): T *: EmptyTuple
def fromArray[T](xs: Array[T]): Tuple
def fromIArray[T](xs: IArray[T]): Tuple
def fromProduct(product: Product): Tuple
def fromProductTyped[P <: Product](p: P)(using m: Mirror.ProductOf[P]): m.MirroredElemTypesFactory methods for creating tuples from various sources.
type Head[X <: Tuple] // First element type
type Tail[X <: Tuple] <: Tuple // All but first element
type Init[X <: Tuple] <: Tuple // All but last element
type Last[X <: Tuple] // Last element type
type Elem[X <: Tuple, N <: Int] // Element at index Ntype Append[X <: Tuple, Y] <: NonEmptyTuple
type :*[X <: Tuple, Y] = Append[X, Y] // Infix append
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple
type ++[X <: Tuple, +Y <: Tuple] = Concat[X, Y] // Infix concat
type Size[X <: Tuple] <: Int
type Reverse[X <: Tuple] <: Tuple
type Take[T <: Tuple, N <: Int] <: Tuple
type Drop[T <: Tuple, N <: Int] <: Tuple
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple
type Filter[Tup <: Tuple, P[_ <: Union[Tup]] <: Boolean] <: Tuple
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple
type Union[T <: Tuple] // Union of all element types
type Fold[Tup <: Tuple, Z, F[_, _]]opaque type NamedTuple[N <: Tuple, +V <: Tuple] >: V <: AnyNamedTuple = V
opaque type AnyNamedTuple = Any
type Empty = NamedTuple[EmptyTuple, EmptyTuple]Named tuples provide field names as part of the type, enabling type-safe field access.
object NamedTuple:
def apply[N <: Tuple, V <: Tuple](x: V): NamedTuple[N, V]
def build[N <: Tuple]()[V <: Tuple](x: V): NamedTuple[N, V]
val Empty: Emptyextension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]):
def toTuple: V
def apply(n: Int): Elem[NamedTuple[N, V], n.type]
def size: Size[NamedTuple[N, V]]
def head: Head[NamedTuple[N, V]]
def tail: Tail[NamedTuple[N, V]]
def last: Last[NamedTuple[N, V]]
def init: Init[NamedTuple[N, V]]
def take(n: Int): Take[NamedTuple[N, V], n.type]
def drop(n: Int): Drop[NamedTuple[N, V], n.type]
def ++[N2, V2](that: NamedTuple[N2, V2])(using Tuple.Disjoint[N, N2] =:= true): Concat[...]
def map[F[_]](f: [t] => t => F[t]): Map[NamedTuple[N, V], F]
def reverse: Reverse[NamedTuple[N, V]]
def zip[V2](that: NamedTuple[N, V2]): Zip[NamedTuple[N, V], NamedTuple[N, V2]]type Names[X <: AnyNamedTuple] <: Tuple // Extract field names
type DropNames[NT <: AnyNamedTuple] <: Tuple // Extract values
type From[T] <: AnyNamedTuple // Convert class fields to named tuple// Creating tuples
val empty = EmptyTuple
val single = Tuple("hello")
val triple = ("Alice", 25, true)
// Accessing elements
val first = triple.head // "Alice"
val rest = triple.tail // (25, true)
val last = triple.last // true
val second = triple.apply(1) // 25
// Adding elements
val extended = triple :* "Engineer" // ("Alice", 25, true, "Engineer")
val prepended = "Dr." *: triple // ("Dr.", "Alice", 25, true)
// Tuple operations
val size = triple.size // 3
val reversed = triple.reverse // (true, 25, "Alice")
val firstTwo = triple.take(2) // ("Alice", 25)
val lastTwo = triple.drop(1) // (25, true)import scala.compiletime.constValue
type MyTuple = String *: Int *: Boolean *: EmptyTuple
val size: 3 = constValue[Tuple.Size[MyTuple]]
type FirstElement = Tuple.Head[MyTuple] // String
type RestElements = Tuple.Tail[MyTuple] // Int *: Boolean *: EmptyTuple// Creating named tuples with literal syntax
val person = (name = "Bob", age = 30, active = true)
// Type-safe field access
val name: String = person.name
val age: Int = person.age
// Operations preserve names
val reversed = person.reverse // (active = true, age = 30, name = "Bob")
val older = person.map([t] => (x: t) => x match
case age: Int => age + 1
case other => other
) // (name = "Bob", age = 31, active = true)
// Concatenation requires disjoint names
val address = (street = "Main St", city = "Boston")
val fullInfo = person ++ address
// (name = "Bob", age = 30, active = true, street = "Main St", city = "Boston")def processTuple[T <: Tuple](t: T): String =
t.toList.mkString(", ")
def tupleMap[T <: Tuple, F[_]](t: T)(f: [U] => U => F[U]): Tuple.Map[T, F] =
t.map(f)
// Usage
val data = ("hello", 42, true)
processTuple(data) // "hello, 42, true"
val lengths = tupleMap(("abc", "hello", "x"))([T] => (s: T) => s match
case str: String => str.length
case other => 0
) // (3, 5, 1)def analyzeTuple(t: Tuple): String = t match
case EmptyTuple => "empty"
case single *: EmptyTuple => s"single: $single"
case first *: second *: EmptyTuple => s"pair: $first, $second"
case head *: tail => s"multiple: $head and ${tail.size} more"
// With named tuples
def analyzeUser(user: AnyNamedTuple): String = user match
case person if person.toTuple.size == 3 => "Person with 3 fields"
case _ => "Other structure"val tuple = ("a", "b", "c")
// Convert to collections
val array = tuple.toArray // Array("a", "b", "c")
val list = tuple.toList // List("a", "b", "c")
val iarray = tuple.toIArray // IArray("a", "b", "c")
// From collections
val fromArray = Tuple.fromArray(Array(1, 2, 3))
val fromProduct = Tuple.fromProduct(("x", "y"))// Filter tuple elements by type predicate
type IsString[X] <: Boolean = X match
case String => true
case _ => false
type MixedTuple = Int *: String *: Boolean *: String *: EmptyTuple
type StringsOnly = Tuple.Filter[MixedTuple, IsString] // String *: String *: EmptyTuple
// Map over tuple types
type ToOption[X] = Option[X]
type OptionTuple = Tuple.Map[MixedTuple, ToOption]
// Option[Int] *: Option[String] *: Option[Boolean] *: Option[String] *: EmptyTuple
// Fold tuple types
type StringConcat[X, Y] = (X, Y) match
case (String, String) => String
case _ => String
type AllStrings = String *: String *: String *: EmptyTuple
type ConcatResult = Tuple.Fold[AllStrings, String, StringConcat] // StringThis 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.