Kotlin quadruple, quintuple, etc. for destructuring

I found it easiest to just code-gen the n-tuples needed. Use-case was functional extension methods for things like memoization, etc.

data class NTuple2<T1, T2>(val t1: T1, val t2: T2)

data class NTuple3<T1, T2, T3>(val t1: T1, val t2: T2, val t3: T3)

data class NTuple4<T1, T2, T3, T4>(val t1: T1, val t2: T2, val t3: T3, val t4: T4)

data class NTuple5<T1, T2, T3, T4, T5>(val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5)

data class NTuple6<T1, T2, T3, T4, T5, T6>(val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6)

And then generate the necesssary construction-helpers:

infix fun <T1, T2> T1.then(t2: T2): NTuple2<T1, T2>
{
    return NTuple2(this, t2)
}

infix fun <T1, T2, T3> NTuple2<T1, T2>.then(t3: T3): NTuple3<T1, T2, T3>
{
    return NTuple3(this.t1, this.t2, t3)
}

infix fun <T1, T2, T3, T4> NTuple3<T1, T2, T3>.then(t4: T4): NTuple4<T1, T2, T3, T4>
{
    return NTuple4(this.t1, this.t2, this.t3, t4)
}

infix fun <T1, T2, T3, T4, T5> NTuple4<T1, T2, T3, T4>.then(t5: T5): NTuple5<T1, T2, T3, T4, T5>
{
    return NTuple5(this.t1, this.t2, this.t3, this.t4, t5)
}

infix fun <T1, T2, T3, T4, T5, T6> NTuple5<T1, T2, T3, T4, T5>.then(t6: T6): NTuple6<T1, T2, T3, T4, T5, T6>
{
    return NTuple6(this.t1, this.t2, this.t3, this.t4, this.t5, t6)
}

So I could then do:

val nTuple4 = 1 then 2 then "foo" then "bar"

Resulting in:

val nTuple4: NTuple4<Int, Int, String, String>

Basics

Let's see how destructuring works:

Kotlin defines a convention for this, i.e. componentX() operator functions are an example of the principle of conventions used in Kotlin in many places. These componentX() functions are used by the compiler for the initialization of variables in destructuring declarations.

For example in Pair<A,B> these functions look as follows:

operator fun component1(): A = first 

operator fun component2(): B = second

As you can see these are operators, specially handled functions. These componentX() functions can be provided by the developer and will automatically be produced by the compiler for data classes. Pair also is such a data class btw.

Answer

Thus, just go ahead and use data classes whenever you need more than a Triple.

For example, a class MultiComponent defined as this:

data class MultiComponent(val x: Int, val y: Int, val z: Int, val a: Int, val b: Int, val c: Int)

will be compiled to a class with functions component1(), component2(), ..., component6() and can be used in destructuring declarations:

val (q, w, e, r, t, z) = MultiComponent(1, 2, 3, 4, 5, 6)

In contrast to Scala, Kotlin does not have n-tuples for values higher than 3 defined. You've correctly identified Pair and Triple.

Kotlin favors using data classes for these use cases, according to this blog post. So yes, you'll have to define a data class in order to do what you want, there is no Quadruple. I'd personally argue that defining your own data class is more clear, and will end up being compiled and used the same way a hypothetical Quadruple would anyway, under the covers.

As for destructuring data classes, Kotlin supports that as well:

data class Thingy(val a: String, val b: String, val c: String, val d: String)
val t = Thingy("A", "B", "C", "D")
val (aa, bb, cc, dd) = t

Tags:

Kotlin

Rx Java