Memoization

If our function always returns the same output for the same input, we could easily map between previous input and output, and use it as a cache. That technique is called memoization:

class Summarizer {
private val resultsCache = mutableMapOf<List<Int>, Double>()

fun summarize(numbers: List<Int>): Double {
return resultsCache.computeIfAbsent(numbers, ::sum)
}

private fun sum(numbers: List<Int>): Double {
return numbers.sumByDouble { it.toDouble() }
}
}

We use a method reference operator, ::, to tell computeIfAbsent to use the sum() method in the event that input wasn't cached yet. 

Note that sum() is a pure function, while summarize() is not. The latter will behave differently for the same input. But that's exactly what we want in this case:

val l1 = listOf(1, 2, 3)
val l2 = listOf(1, 2, 3)
val l3 = listOf(1, 2, 3, 4)

val summarizer = Summarizer()

println(summarizer.summarize(l1)) // Computes, new input
println(summarizer.summarize(l1)) // Object is the same, no compute
println(summarizer.summarize(l2)) // Value is the same, no compute
println(summarizer.summarize(l3)) // Computes

The combination of immutable objects, pure functions, and plain old classes provides us with a powerful tool for performance optimizations. Just remember, nothing is free. We only trade one resource, CPU time, for another resource, memory. And it's up to you to decide which resource is more expensive for you in each case.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.74.231