There are times when you're using chaining and you want to pass all the every chain result to the last chain
without creating redundant types that will be only used once inside these chains
Note:: You can always do that by nesting chains which looks ugly
This can also be achieved without copying using one data class with mutable members
data class Info(val id:Int?=null,val name:String="", val country:String?=null)
fun main(){
Single.just(1).map {Info(id=1) }
.flatMap {params-> Single.just("Ahmed").map { params.copy(name=it) } }
.flatMap { params->Single.just("Egypt").map { params.copy(country=it)} }
.subscribe {params->
print(params.country!!)
print(params.name)
}
}- Most readable and clean approach
- Can return the type outside of the function scope if the data class
- If you're returning unrelevant data through the chain your class will have no meaning
- If you don't want to return all the chains results and each chain should return different mix of types you may need to declare multiple classes
- You will have to write the class declaration upfront
Making generic object with named variables of mutliple types using map collection
You can use Kotlin 'to' infix function to creat Pair or you can make your own function to force the key type to be string which you can see in 'eq' function
typealias NamedEntry = Pair<String,Any>
typealias DynamicObj = MutableMap<String,Any>
infix fun String.eq(value:Any):NamedEntry = NamedEntry(this,value)
infix fun NamedEntry.with(other:NamedEntry):DynamicObj = mutableMapOf(this,other)
infix fun DynamicObj.with(other:NamedEntry):DynamicObj {
this[other.first]=other.second
return this
}
fun <T> DynamicObj.valueOf(key:String):T = this[key]!! as T
fun main(){
var map=("age" to 25) with ("name" to "Ahmed") with ("country" to "Egypt")
map with ("id" to 1000)
print(map.valueOf<String>("name"))
print(map.valueOf<Int>("age"))
Single.just(1).map { ("id" eq it) }
.flatMap {params-> Single.just("Ahmed").map { params.with("name" eq it) } }
.flatMap { params->Single.just("Egypt").map { params.with("country" eq it) } }
.subscribe {params->
print(params.valueOf<String>("name"))
print(params.valueOf<Int>("id"))
}
}- No need to declare the type upfront just append the data to the map
- Returning different result for each chain is not an issue
- Extracting variables is not type safe
- No AutoCompletion for finding variables
- Any typo in the key of the map won't be noticed until the app crashes
- Returning the dynamic object as result of a function outside chains scope .. Make it ambigous of which key's are used
Kotlin provide object keyword which make it easier to extend
fun main(){
Single.just(1)
.flatMap {id-> Single.just("Ahmed").map { object{val name =it ; val id = id} }
.flatMap { params->Single.just("Egypt").map { object{val name =params.name; val id = params.id; val country=it}
.subscribe {params->
print(params.name)
print(params.id)
}
}- it solves all the proplems of the first approach
- Same problem with returning the type out side of the scope as this type won't be available outside of the chain scope .. we can use the same solution
- You have to redeclare the objects fields every time you want to append new member to it
ReactiveX/RxJava#2931
ReactiveX/RxJava#2452
reduxjs/react-redux#278
https://github.com/stealthcode/RxJavaMulti
https://github.com/pakoito/Komprehensions
https://github.com/pakoito/Komprehensions/blob/master/komprehensions-rx2/src/main/kotlin/com/pacoworks/komprehensions/rx2/KomprehensionsRx.kt