Skip to content

Commit

Permalink
Move NonEmptyTuple members into Tuple
Browse files Browse the repository at this point in the history
Addressing #19175

The motivation for this has already been established, among other things:
- the corresponding type level operations already use `Tuple` as upper bound;
- the corresponding `NamedTuple` operations also do not make a distinction;
- these operations are no more unsafe than other operations already available
  on `Tuple`, such as `drop`

Note this should _not_ be a problem for binary compatibility,
as both `Tuple` and `NonEmptyTuple` are erased to `Product`s
(see `defn.specialErasure`).
  • Loading branch information
EugeneFlesselle committed Jul 31, 2024
1 parent 32e4056 commit 1cc3ea3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 34 deletions.
4 changes: 1 addition & 3 deletions library/src/scala/NamedTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ object NamedTupleDecomposition:
extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V])
/** The value (without the name) at index `n` of this tuple */
inline def apply(n: Int): Tuple.Elem[V, n.type] =
inline x.toTuple match
case tup: NonEmptyTuple => tup(n).asInstanceOf[Tuple.Elem[V, n.type]]
case tup => tup.productElement(n).asInstanceOf[Tuple.Elem[V, n.type]]
x.toTuple.apply(n).asInstanceOf[Tuple.Elem[V, n.type]]

/** The number of elements in this tuple */
inline def size: Tuple.Size[V] = x.toTuple.size
Expand Down
52 changes: 25 additions & 27 deletions library/src/scala/Tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,30 @@ sealed trait Tuple extends Product {
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
runtime.Tuples.cons(x, this).asInstanceOf[H *: This]

/** Get the i-th element of this tuple.
* Equivalent to productElement but with a precise return type.
*/
inline def apply[This >: this.type <: Tuple](n: Int): Elem[This, n.type] =
runtime.Tuples.apply(this, n).asInstanceOf[Elem[This, n.type]]

/** Get the head of this tuple */
inline def head[This >: this.type <: Tuple]: Head[This] =
runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]]

/** Get the initial part of the tuple without its last element */
inline def init[This >: this.type <: Tuple]: Init[This] =
runtime.Tuples.init(this).asInstanceOf[Init[This]]

/** Get the last of this tuple */
inline def last[This >: this.type <: Tuple]: Last[This] =
runtime.Tuples.last(this).asInstanceOf[Last[This]]

/** Get the tail of this tuple.
* This operation is O(this.size)
*/
inline def tail[This >: this.type <: Tuple]: Tail[This] =
runtime.Tuples.tail(this).asInstanceOf[Tail[This]]

/** Return a new tuple by concatenating `this` tuple with `that` tuple.
* This operation is O(this.size + that.size)
*/
Expand Down Expand Up @@ -304,33 +328,7 @@ case object EmptyTuple extends Tuple {
}

/** Tuple of arbitrary non-zero arity */
sealed trait NonEmptyTuple extends Tuple {
import Tuple.*

/** Get the i-th element of this tuple.
* Equivalent to productElement but with a precise return type.
*/
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] =
runtime.Tuples.apply(this, n).asInstanceOf[Elem[This, n.type]]

/** Get the head of this tuple */
inline def head[This >: this.type <: NonEmptyTuple]: Head[This] =
runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]]

/** Get the initial part of the tuple without its last element */
inline def init[This >: this.type <: NonEmptyTuple]: Init[This] =
runtime.Tuples.init(this).asInstanceOf[Init[This]]

/** Get the last of this tuple */
inline def last[This >: this.type <: NonEmptyTuple]: Last[This] =
runtime.Tuples.last(this).asInstanceOf[Last[This]]

/** Get the tail of this tuple.
* This operation is O(this.size)
*/
inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] =
runtime.Tuples.tail(this).asInstanceOf[Tail[This]]
}
sealed trait NonEmptyTuple extends Tuple

@showAsInfix
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
Expand Down
8 changes: 4 additions & 4 deletions library/src/scala/runtime/Tuples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ object Tuples {
}
}

def tail(self: NonEmptyTuple): Tuple = (self: Any) match {
def tail(self: Tuple): Tuple = (self: Any) match {
case xxl: TupleXXL => xxlTail(xxl)
case _ => specialCaseTail(self)
}
Expand Down Expand Up @@ -558,16 +558,16 @@ object Tuples {
}
}

def init(self: NonEmptyTuple): Tuple = (self: Any) match {
def init(self: Tuple): Tuple = (self: Any) match {
case xxl: TupleXXL => xxlInit(xxl)
case _ => specialCaseInit(self)
}

def last(self: NonEmptyTuple): Any = (self: Any) match {
def last(self: Tuple): Any = (self: Any) match {
case self: Product => self.productElement(self.productArity - 1)
}

def apply(self: NonEmptyTuple, n: Int): Any =
def apply(self: Tuple, n: Int): Any =
self.productElement(n)

// Benchmarks showed that this is faster than doing (it1 zip it2).copyToArray(...)
Expand Down

0 comments on commit 1cc3ea3

Please sign in to comment.