While programming lcarswm, I ran into a scenario where I would have liked to have something like Java's Closable. But I needed it in Kotlin/Native and I needed it on an application global scale.
Something that showed itself to me during development was this: there are quite a few resources that need to be requested from Xlib and the other libraries or setup in another way and kept until the end of the program, where they need to be freed again, often calling also a library funtion. In the long startup routine were also certain points, where the program needs to be aborted, if the resource is unaccessible. If the program is aborted, previously acquired resources must also be freed.
The initial solutionInitially, the scenario was solved by explicitly releasing everything during shutdown and having if branches in the startup that explicitly cleaned up resources that were acquired before those conditions, if they were not met. It's roughly shown in the following figure.
The more resources are required, the uglier this approach looks due to a lot of code duplication. I wanted something more slim and semi-automatic.
As an additional requirement, the resources generally should be released in reversed order of acquiring them.
My basic idea/wish was this: whenever an acquired resource needs to be cleanup that should be taken care of at the moment of the acquisition. I was thinking about creating an interface, but sometimes resources are directly requested from the same libraries using different functions for different resources at different times. An interface would have not worked here unless creating an extra class for each resource. What looked more flexible and convenient to me was a solution with extension function.
First of all, the resources that need to be cleaned up need to be tracked or alternatively, the clean-up itself can be tracked. I decided for the later in form of clean-up functions and called it closables as shown in the next figure:
When shutting down at any point in the program all the closables get called in reversed order by calling the following global clean-up function. Whatever has been instantiated at the point of calling the function shown in the next figure, it will get cleaned up and it is not required to know what exactly that is.
So much for the straightforward part. What is missing is the registration of the closables. This is done via a generic extension function. This way everything automatically gets the extension function. It also returns the object on which it was called which allows for chaining of calls on the object. All the registration function requires is a function from the extended class itself, that has no argument and no return value and implements the cleanup. This function will be kept in the list of closables. Here is the implementation:
Finally, in lcarswm closables are used for instance like this:
The full code can be found on Github in the lcarswm repository: closable.kt.