Skip to content

jbarop/kraii

Repository files navigation

kraii - Kotlin Resource Acquisition Is Initialization

Proof Of Concept to implement the RAII pattern in Kotlin using a compiler plugin.

Motivation

Java utilizes garbage collection for memory management. When an object is no longer needed, it is automatically freed at some point. However, we have limited influence on how and when.

But how do we handle non-heap resources such as files, socket connections, or even hardware? How should the garbage collector evaluate whether the graphics card still has enough free memory?

We are unable to use java.lang.Object.finalize(). The finalization mechanism is problematic and marked as deprecated. There are no guarantees about the order and timing of finalization. The finalize method may not be called until after an indefinite delay, if at all. The documentation points out that non-heap resources should be released by implementing java.lang.AutoClosable.

Java (try (var r = new Resource()) { …​ }) and Kotlin (Resource().use { …​ }) provide tools to automatically close or release instances of AutoClosable. However, this is limited to the scope of a single function. If we have many non-heap resources associated with the lifecycle of objects, then they need to be released explicitly. This is error-prone and can lead to leaks.

"Resource Acquisition Is Initialization" (RAII) is a resource management strategy invented by Bjarne Stroustrup for C++. Rust has adopted RAII as a core language concept through its ownership system and the Drop trait, making deterministic resource cleanup a fundamental part of the language. In both languages, each object is responsible for managing its own resources, ensuring that any resources are released as early as possible.

Example

Running the Sample

git clone git@github.com:jbarop/kraii.git
cd kraii/sample
./gradlew run

Code

/**
 * A temporary file as an example for a non-heap
 * resource.
 */
class ExternalResource : AutoCloseable {

  private val tempFile = createTempFile()

  init {
    println("$tempFile has been created.")
  }

  /**
   * The implementation of [AutoCloseable.close] is
   * responsible for freeing the resource. In this
   * case the file needs to be removed.
   */
  override fun close() {
    tempFile.deleteExisting()
    println("$tempFile has been deleted.")
  }
}

/**
 * A class which uses other resources.
 *
 * It extends the [AutoCloseable] interface, but does
 * implement [AutoCloseable.close]. This is done
 * automatically by the compiler plugin.
 */
class ResourceOwner : AutoCloseable {

  @Scoped
  private val firstResource = ExternalResource()

  @Scoped
  private val secondResource = ExternalResource()
}

fun main() {
  @Scoped val owner = ResourceOwner()
  println("Hello World!")
  // owner.close() is called automatically when the function ends
}

Output

/tmp/2214526001872441198.tmp has been created.
/tmp/15561580686778472.tmp has been created.
Hello World!
/tmp/15561580686778472.tmp has been deleted.
/tmp/2214526001872441198.tmp has been deleted.

The plugin generates ResourceOwner.close() which closes secondResource and firstResource in reverse declaration order. The @Scoped local variable in main ensures owner.close() is called automatically when the function ends.

IntelliJ IDEA Setup

IntelliJ IDEA may show errors for missing close() methods that are generated by the compiler plugin. To fix this, set the following registry flag:

  1. Open the registry: HelpFind Action…​ → type Registry…​

  2. Find the key kotlin.k2.only.bundled.compiler.plugins.enabled

  3. Set it to false

See KTIJ-29248 for details.

Caveats / ToDos / Ideas

This is a proof of concept and cannot be used productively in its current state. The plugin has not been extensively tested nor released.

  • There is no error handling.

  • Support Kotlin Native

If you are interested in this topic, I would be very happy to hear from you.

About

Proof Of Concept to implement the RAII pattern in Kotlin using a compiler plugin.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages