Kotlin for Lunch - Atomic<T>
“Kotlin for Lunch” collects Kotlin exercises, usage patterns, or “the Kotlin way” to solve development issues. This article should be short enough to have fun with Kotlin during a short lunch break.
We are here today: Kotlin > Coroutines > Concurrency
Kotlins Mutex
is a nice idea when you need to lock a code block from beeing executed at the same time, but the code examples show them almost always together with a variable:
So why not have a builtin variable that can only be modified when the Mutex
is locked? If you look at the Kotlin docs, you find AtomicInt
, AtomicLong
, and a few others — but not for all platforms (“native” only), and nowhere a generic Atomic<T>
. Its time to change that.
So lets introduce Atomic<T>
, an object that allows you to modify the value of type T
, when no one else can. Even better, lets inherit from Mutex
, so every Atomic<T>
becomes also a Mutex and you get the Mutex functions for free.
Mutex()
is an extension function and provides a Mutex
object that implements that interface. By delegating the implementation to this object, we save all the function forwarding and get a very slim class definition. All functions and properties from Mutex
are available without any boilerplate.
Lets try it out with some code:
Works nice. But wait a second, having to call a variable inside a lambda that was called from that very same variable doesn’t look good, or as others say, it smells.
It would be much more cool (and maybe less error prone and more intuitive) if we would have this
referring to our Atomic<T>
or T
object itself.
We need a function that allows us the set the new value and a function that let us read or modify our T
as this
. I came up with these two:
withLock
allows us to use a lambda that can use value
as this
. That enables you to use functions from T
without any boilerplate. You can either manipulate this directly or just read (and return) whatever you need in a consistent blocked way.
setWithLock
allows us to put in a lambda that receives the current value of our Atomic<T>
and saves the returned value as new state. That makes nicer code as your T
object stays immutable.
An interesting code gimmick of Kotlin is the way to call the original Mutex.withLock
function. Issue here - Mutex.withLock
is not a member, but an extension function (see also the extra import
line). So you can’t reach it with super.withLock
, but you need to cast your object to a Mutex
, to reach out for Mutex.withLock
.
Everything put together with an example program to run:
Hope you enjoyed. Ideas and remarks are welcome.