Reputation: 1935
I have created a helper method buildChain
which essentially creates a
chain of objects given that they implement the interface IChain<T>
and set the contracts next
member
The Code
interface Chain<T> {
var next: T?
operator fun plus(next: T): T?
}
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
var next: T? = null
members.forEachIndexed { i, t ->
if (i == 0) {
next = first + t
} else {
next = next?.run { this + t }
}
}
return first
}
Implementation example
data class Person(val name: String) : Chain<Person> {
override var next: Person? = null
override fun plus(next: Person): Person? {
this.next = next
return next
}
}
fun createPersonChain()
= buildChain(Person("Bob"), Person("Bitzy"), Person("Blitzy"))
Implementaion output example
@JvmStatic fun main(args: Array<String>) {
var first = createPersonChain()
// first.name = "Bob"
// first.next.name = "Bitzy"
// first.next.next.name = "Blitzy"
}
Is there a functional
or simpler
way for acheiving the code
above keeping the implementaion usage the same?
Upvotes: 8
Views: 4142
Reputation: 31
Try apply{}
. In the {}
block pass your methods separated with ';'
Object().apply{ method1(); signUp(user) }
Upvotes: 3
Reputation: 147951
A functional idiom fold suits your needs well: it takes an initial item and then iterates over the other items, maintaining an accumulated value, which is updated on each item being processed with the function you provide.
In Kotlin, it is fold
extension function for Iterable
, Sequence
or Array
.
You can use it in the following way:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
members.fold(first as T?) { acc, i -> acc?.let { it + i } }
return first
}
Here first as T?
cast is needed for the accumulator type to be inferred as nullable T?
, because plus
in your Chain<T>
returns nullable value (by the way, is it necessary?).
You can also use foldRight
, which just iterates in the opposite order:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members)
.foldRight(null as T?) { i, acc -> acc?.let { i + acc }; i }
And there are reduce
and reduceRight
with similar semantics but using the first and the last item respectively for the accumulator's initial value. Here's the example with reduceRight
:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members).reduceRight { i, acc -> i.apply { plus(acc) } }
Upvotes: 10