# Scala 3: split tuple to exact types

My objective is to flatten a `Tuple` and get its flattened version with the exact tyoe.
So the following should compie:

``````    val c1: Tuple4[Int, Int, Char, Char] = flatten( ((1,2), ('a', 'b')) )
``````

I cannot get the types correct. I seem to only get the top type `Tuple`.
So I experimented with `concat` to check the typing. The following work correctly:

``````  def concat[T1 <: Tuple, T2 <: Tuple](t1: T1, t2: T2): Tuple.Concat[T1, T2] = {
t1 ++ t2
}

def concat2[S1 <: Tuple, S2 <: Tuple, T1 <: Tuple, T2 <: Tuple](s1: S1, s2: S2, t1: T1, t2: T2):
Tuple.Concat[Tuple.Concat[S1, S2], Tuple.Concat[T1, T2]] = {
val u1 = concat(s1, s2)
val u2 = concat(t1, t2)
u1 ++ u2
}

def concat2a[S1 <: Tuple, S2 <: Tuple, T1 <: Tuple, T2 <: Tuple](s1: S1, s2: S2, t1: T1, t2: T2):
Tuple.Concat[Tuple.Concat[S1, S2], Tuple.Concat[T1, T2]] = {
val u1:Tuple.Concat[S1, S2]  = concat(s1, s2)
val u2:Tuple.Concat[T1, T2] = concat(t1, t2)
u1 ++ u2
}
``````

So on further investigation I tried this:

``````  def split[S1  <: Tuple, S2 <: Tuple, O <: Tuple](o: O): (S1, S2) = {
o match {
case (s@(h1 *: t2 *: _)) *: t =>
println(s"s = \$s")
println(s"t = \$t")
(s, t)
}
}
``````
``````[error]     |         ^
[error]     |         Found:    (s : Any *: Tuple)
[error]     |         Required: S1
[error]     |
[error]     |         where:    S1 is a type in method split with bounds <: Tuple
[error] -- [E007] Type Mismatch Error: /home/hmf/Test.scala:126:12
[error] 126 |        (s, t)
[error]     |            ^
[error]     |           Found:    (t : Tuple)
[error]     |           Required: S2
[error]     |
[error]     |           where:    S2 is a type in method split with bounds <: Tuple

``````

One of the issues I see is that the tuple is constructed with a head and tail, and this head need not be a tuple - hence the `Any` (if this is not so please correct me).

Another issue is that when I pattern match I get general Tuple which does not match a specific `<: Tuple`.

So my question is, is their any way I can match and retain the most specific type information?

TIA

Investigating this further I tried the use of `transparent inlne` so:

``````  transparent inline def split[O <: Tuple](inline o: O) = {
o match {
case (s@(_ *: _)) *: t =>
println(s"s = \$s")
println(s"t = \$t")
(s, t)
}
}
``````

And it seems to work: This compiles:

``````    val (s1: Tuple2[Int, Int], s2: Tuple1[Int]) = split(((1,2),3))
``````

However when I use an inlined match:

``````  transparent inline def split[O <: Tuple](inline o: O) = {
inline o match {
case (s@(_ *: _)) *: t =>
println(s"s = \$s")
println(s"t = \$t")
(s, t)
}
}
``````

I get:

``````[error] -- Error: /Test.scala:217:55
[error] 217 |    val (s1: Tuple2[Int, Int], s2: Tuple1[Int]) = split(((1,2),3))
[error]     |                                                  ^^^^^^^^^^^^^^^^
[error]     |cannot reduce inline match with
[error]     | scrutinee:  Tuple2.apply[(Int, Int), Int](Tuple2.apply[Int, Int](1, 2), 3) : ((Int, Int), Int)
[error]     | patterns :  case *:.unapply[Any, Tuple](s @ *:.unapply[Any, Tuple](_, _):Any *: Tuple, t @ _):
[error]     |  Any *: Tuple
[error]     | This location contains code that was inlined from HyperParameters.scala:59
[error] one error found
1 targets failed
``````

I am assuming the value is statically defined during compile time so the match should work. Can anyone explain why it is not so. I suspect this is due to the same issue above.

TIA

I think NonEmptyTuple has the tools to do this.

Couldn’t figure it out. I see an apply, head and tail with corresponding types. I confess when I delved into the run-time code I got lost. I also did not find any uses of matching (TupleXXL is array based and the special cases use access fields).

Also, something else has baffled me in this regard. The class:

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

Seems to suggest an `HList`of sorts, but I find it is only used at the type level (see `Tuple.Concat` used above). Maybe someone conversant in type level programming + Scala 3 (Dotty) can explain.

Thanks