How to name components of a Pair
Asked Answered
U

6

28

Given the Pair val coordinates = Pair(2, 3), is it possible to name each value so I can do something like coordinates.x to return 2? Or is coordinates.first the only way to access that first value?

Ullrich answered 7/1, 2018 at 0:52 Comment(0)
D
30

This is not supported. You should write a wrapper (data) class for that purposes or you could use Kotlin destructuring declarations:

val (x, y) = coordinates
println("$x;$y")

See more here.

Dawdle answered 7/1, 2018 at 0:55 Comment(0)
C
13

Another solution is to define an object with meaningful extensions for Pair<A, B> and to bring these extensions into the context using with(...) { ... }.

object PointPairs {
    val <X> Pair<X, *>.x get() = first
    val <Y> Pair<*, Y>.y get() = second
}

And the usage:

val point = Pair(2, 3)

with(PointPairs) {
    println(point.x)
}

This allows you to have several sets of extensions for the same type and to use each where appropriate.

Clergy answered 7/1, 2018 at 22:23 Comment(0)
I
11

The definition of Pair in the Kotlin stdlib is as follows:

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable

So, if you have an instance p of type Pair, you can access the first property only as p.first. However, you can use a Destructuring Declaration like this:

val (x, y) = p

This is made possible because Pair is a data class. Every argument of the primary constructor of a data class gets a componentX() method, where X is the index of the parameter. So the above call can be expressed like this:

val x = p.component1()
val y = p.component2()

This makes it absolutely independent from the actual name of the parameter.

If you, however, want to be able to write p.x, you'll have to go ahead and create your own data class (or use a library):

data class Point(val x : Double, val y : Double)
Ihram answered 7/1, 2018 at 1:35 Comment(0)
C
9

I want to propose an alternative, which should be applied if the renaming is desired only in a certain scope.

You can create a simple extension higher-order function enabling the naming in a scope, passed as a lambda-argument:

fun <F, S> Pair<F, S>.named(block: (F, S) -> Unit) = block(first, second)

Now, a Pair can be called with a lambda, which is invoked with its components that are name-able on caller-site:

val pair = Pair(2, 3)
pair.named { x, y ->
    println("my pair: ($x,$y)")
}

It's even possible to apply the invoke convention:

operator fun<F, S> Pair<F, S>.invoke(block: (F, S) -> Unit) = block(first, second)

Now, the Pair can be invoked directly:

val pair = Pair(2, 3)
pair { x, y ->
    println("my pair: ($x,$y)")
}
Cupel answered 7/1, 2018 at 7:42 Comment(0)
O
4

The Kotlin documetation says:

The standard library provides Pair and Triple. In most cases, though, named data classes are a better design choice, because they make the code more readable by providing meaningful names for properties.

Since Pair is final you can unfortunately not inherit from it, but I would suggest to create a dedicated class Point:

data class Point<T>(val x: T, val y: T)

to represent a point. This way wherever you use it you are always forced to access it using the meaningful names.

Use it:

val myPoint = Point(1.0, 2.0)
println("This is the horizontal coordinate: ${myPoint.x}")
Overflight answered 15/1, 2018 at 21:15 Comment(0)
B
4

another thing i enjoy doing here to help code readability, is to use typealias (or more recently inline classes but still experimental at this time)

so you could do this:

typealias Radius = Double?
typealias Area= Float

then do: Pair<Area,Radius> so its much more readable, but for access description i would do data class.

you could take it one step further:

typealias  DimensionsPair = Pair<Area,Radius>

note that i think inline class here would bring better type safety.

Billboard answered 14/1, 2020 at 4:42 Comment(2)
Nice approach as it provide a bit more clear self documentation to code. Only drawback is that you still have to use the .first and .second to access each pair part.Extenuatory
No. I never do that. Instead you can destruct the pair. https://mcmap.net/q/487793/-how-to-name-components-of-a-pairBillboard

© 2022 - 2024 — McMap. All rights reserved.