1

I've come accross a case where I want to "chain" mutliple delegates (piping the output of one into the other).

This seems to be possible:

private val errorLogList by listSO(listOf<StateObject<Luxeption>>(), SODest.NONE, publicSOAccessRights())
val errorLog: StateObject<List<StateObject<Luxeption>>> by addToSet(errorLogList)

However, this does not look too well :). I'd like to do it in one line like this:

val errorLog: StateObject<List<StateObject<Luxeption>>> by addToSet(
   listSO(listOf<StateObject<Luxeption>>(), SODest.NONE, publicSOAccessRights())
)

My question: Is this type of creating properties through delegates possible in Kotlin?


Here are both implementations of my delegates:

addToSet:

open class ChildSOReturner {

    val set: Set<StateObject<*>> = setOf()

    inline fun <reified T> addToSet(so: T) = object: ReadOnlyProperty<Any?, T> {
        override operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
            if (thisRef is T) {
                set.plus(so)
                return so
            } else throw IllegalArgumentException()
        }
    }
}

listSo:

fun <O> listSO(
    initialState: List<StateObject<O>>,
    soDest: SODest,
    soAccessRights: SOAccessRights
) = object : ReadOnlyProperty<Any?, StateObject<List<StateObject<O>>>> {

    override operator fun getValue(thisRef: Any?, property: KProperty<*>): StateObject<List<StateObject<O>>> {
        val meta = SOMeta(SOId(property.name), soDest, soAccessRights)
        return StateObjectList(initialState, meta)
    }

}
p_0g_amm3_
  • 451
  • 6
  • 14
  • 1
    Related: [How to combine kotlin delegated property: observable, vetoable, and “by map”?](https://stackoverflow.com/questions/52809157/how-to-combine-kotlin-delegated-property-observable-vetoable-and-by-map) – Roland Feb 11 '20 at 13:06

1 Answers1

1

It turned out to be quite tricky, but possible (unless I am missing something, and it isn't tested but the idea should work):

fun <T, U, V> composeProperties(prop: ReadOnlyProperty<T, U>, f: (U) -> ReadOnlyProperty<T, V>) : ReadOnlyProperty<T, V> {
    var props = mutableMapOf<Pair<T, KProperty<*>>, ReadOnlyProperty<T, V>>()
    return object : ReadOnlyProperty<T, V> {
        override operator fun getValue(thisRef: T, property: KProperty<*>): V {
            val prop1 = props.getOrPut(Pair(thisRef, property)) { 
                f(prop.getValue(thisRef, property))
            }
            return prop1.getValue(thisRef, property)
        }
    }
}

And then to use

val errorLog: ... by composeProperties(listSO(...)) { addToSet(it) }
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Is there a way to combine composeProperties(..) { addToSet(it) } into a call like addComposed(..)? I can't seem to figure it out. – p_0g_amm3_ Feb 16 '20 at 20:42