KMemoize is a Kotlin compiler plugin which enables quick-and-easy function memoization without the need for boilerplate code.
- Functions are tagged with the
@Memoizeannotation. - Supports pure top-level, member, local, and anonymous functions :)
- Impure functions can be forcibly memoized by using the
@UnsafeMemoizeannotation. This may lead to unintended behaviour!
- Impure functions can be forcibly memoized by using the
fun factorial(n: Int): Long =
if (n == 0) 1L
else n * factorial(n - 1)
@Memoize
fun factorialMemoized(n: Int): Long =
if (n == 0) 1L
else n * factorialMemoized(n - 1)
fun main() {
val (value, time) = measureTimedValue { (1 .. 40000).sumOf { factorial(it) } }
val (valueMemoized, timeMemoized) = measureTimedValue { (1 .. 40000).sumOf { factorialMemoized(it) } }
println(value == valueMemoized)
println("Non-memoized time: $time")
println("Memoized time: $timeMemoized")
}Console Output:
true
Non-memoized time: 1.483682300s
Memoized time: 10.784501ms
Internally, what's happening is that factorialMemoized is getting compiled to the equivalent of this code 👇
private val factorialMemoized234738315Memory: MutableMap<Int, Long> =
mutableMapOf<Int, Long>()
@Memoize
fun factorialMemoized(n: Int): Long {
if (n !in factorialMemoized234738315Memory) {
factorialMemoized234738315Memory[n] =
if (n == 0) 1L
else n * factorialMemoized(n - 1)
}
return factorialMemoized234738315Memory[n]!!
}The weird 234738315 in factorialMemoized234738315Memory is just the hash code of the function's
IR representation during compilation. This is just to avoid using existing identifiers.
plugins {
id("io.github.ambco-iscte.kmemoize") version "<kmemoize.version>"
}
dependencies {
implementation("io.github.ambco-iscte:kmemoize.api:<kmemoize.version>")
}<dependencies>
<dependency>
<groupId>io.github.ambco-iscte</groupId>
<artifactId>kmemoize.api</artifactId>
<version>${kmemoize.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.2.0</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compilerPlugins>
<plugin>kmemoize</plugin>
</compilerPlugins>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>io.github.ambco-iscte</groupId>
<artifactId>kmemoize.compiler</artifactId>
<version>${kmemoize.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>