Need field alias for re-use holder class


#1

I’m an Android developer, enjoy coding with Kotlin.

There are many classes that have same fields count, no behavior, no state. I want there is a way to re-use classes like this example:

// some classes that without any method, just holder.
class Holder1(var title: TextView, var icon: ImageView)
class Holder2(var content: TextView, var backgroud: ImageView)
class Holder3(var click: Button, var img: ImageView)
class Holder4(var whatever: Button, var foobar: Any)

val old1 = Holder1(view1, view2)
call(old1.icon)

val old2 = Holder2(view3, view4)
call(old2.content)



// now using Generics, but there is no field alias.
class Type2<T1 : Any, T2 : Any>(var first: T1, var second: T2)

val g1 = Type2(view1, view2)
call(g1.first) // need alias for Type2.first.

val g2 = Type2(view3, view4)
call(g2.second) // need alias for Type2.second.




// or some feature like this:
val new1 = With2Fields(view1 named title, view2 named icon)
call(new1.icon) // view2 is ImageView, auto cast to ImageView
val new2 = With3Fields(view3 named contentField, view4 named backgroud, foo named bar)
call(new2.contentField)// view3 is TextView, auto cast to TextView

// or implement with array, not class.
@Suppress("UNCHECKED_CAST")
fun <T> Array<Any>.field(index: Int) = this[index] as T

val arr = arrayOf<Any>(view1, view2)
val f1: TextView = arr.field<TextView>(0)
val f2: ImageView = arr.field<ImageView>(1)

#2

You can use Pair<X, Y> and Triple<X, Y, Z> from the standard library and you can you implement similar classes.
They have methods like component1() and component2(), which allow you to use destructuring, like this:

val (a, b) = Pair(42, "some name")

It’s also quite easy to implement your one data classes:

data class MyPair<A, B>(val first: A, val second: B)

Because you declared it as a data class, the compiler generates operator fun component1() = first and operator fun component2() = second for you.

As for the field(n: Int) methods, it can be done, but I wouldn’t recommend, since it’s not type safe:

data class MyPair<A, B>(val first: A, val second: B) {
    inline fun <reified T> field(n: Int) = when (n) {
        0 -> first as T
        1 -> second as T
        else -> throw IllegalArgumentException()
    }
}

#3

I understand Tuples.kt or data class, but “triple.first, triple.second, componentN…” is not readable. If there is an alias feature for fields, that will be nice.


#4

I’m not sure what exactly is wrong with the existing solution. We’ve intentionally made declaring classes as short as possible in Kotlin, and your example shows that. Your With2Fields example won’t work as you’re showing it, because you’re not specifying any types for the fields, and if you do specify the types, it will immediately become longer than a data class declaration. And if you want to use arrays - well, you can, but you lose all type safety.


#5

Thanks for explanation. I’m not expressed clearly my question. I’m not good at English.

If there is an alias feature for fields or even method, that will be nice.

syntax like this:

alias SomeDataClass#textView = SomeDataClass.component1
alias Pair#textView = Pair.component1()

#6

You can use inline extension properties to create such aliases, but I still don’t understand why you want this. Declaring an actual class requires less code than defining such aliases, and is much more maintainable.


#7

inline function will create method in bytecode,
too much holder classes but different field naming is redundant in my opinion.
Pair, Triple is an choice, but not readable.


#8

No, they are not redundant. When you use a data class, you make it explicit what exactly this data class contains (consider icon and background in your initial example). An alias would be available on any instance of a class such as Pair, even if it doesn’t make sense in the specific context where you’re trying to use it.