GuardedByLock a simple helper to make sure variable is only accessed with lock
A topic of ownership is better covered in Rust Language. Still, such problems are not solved well enough in the JVM world. Let’s consider a trivial shared state access example
We all know the best state is no state. And we tend to decouple tricky things. But of course, there are some places in programs where one finally needs to deal with a state. In reality, it can easily be a complicated state with several different locks in one object.
The common problem here is to make sure fields are accessed with correct locks taken. It is tricky to ensure in Java. It is double tricky to ensure future changes will not break the contract.
JSR-305 and GuardedBy annotations are created to make a binding between state and guards. But those are only to help an IDE to be smarter, those annotations will not turn a mistake into a compilation error.
I’m looking the way to make a compiler to ensure the access is correct.
Java Style solution
In Java, this can be done in the following way. Create a function runWithLock
and make this function accept
an interface with a method like run(State s)
. If necessary a generics can be added to simplify usages.
To implement that one need to extract a state object (which I call State
). Happy Java 1.8 users may benefit
from Lambda syntax. But the approach itself requires a creation of tiny objects (for lambdas, in most cases) on every call.
Such overhead is small, but one may not like it.
An example call code would look like
Let’s try avoid lambdas overhead and to yield a bit better syntax.
Kotlin Style solution
Consider the following implementation in Kotlin
The usage is as follows:
Let’s take a look closer to the runWithLock
call. Here {
and }
are used to
declare an anonymous extension function
of type State.() -> Y
(Y
is a generic type parameter).
Extension function means that in the body of the function we have this
keyword pointing to State
object
instance. And the part value = 5
means we assign the value to State
object property/field.
The inline
keyword here makes Kotlin compiler to
inline
the function body to avoid creating an anonymous function in the compiled code. You may refer to
the previous post for bytecode listing of inline function calls.
With this approach, we avoid creation anonymous classes for Lambdas from one hand. From the other hand,
the Kotlin compiler is in charge of checking a State
object instance in only accessible after necessary
locks are held.
Finally, the bytecode for the main
function is the following. Note. I use IntelliJ IDEA 2017.1 EAP with Kotlin
1.0.6 plugin. The generated bytecode may change with a future version of tools.
As we see from the code, there is NO anonymous class creation.A call to GuardedByLock#runWithLock
was inlined into
the main
function body, meaning less overhead (who’d measure it :).
Conclusion
In the post, I presented GuardedByLock
class in Kotlin. Using it in your project may help to
correctly isolate state and make Kotlin complier checking all possible violations for you.
The only cost is 2 additional object instances: one for GuardedByLock
, and the other one for the State
.