loading...

re: Why I stopped using Coroutines in Kotlin VIEW POST

TOP OF THREAD FULL DISCUSSION
re: kotlinx.coroutines.sync.mutex is a mutex implementation that works with coroutines. If guava was using this mutex implementation, then it might wor...

Nevertheless, recursively loading the same key seems like a strange edge case. One should not query guava from within the loading function that is supposed to retrieve the very same key.

Indeed it is, and not what the developer wants. Which is why guava raises an exception if this case occurs. But take a step back and think about how guava accomplishes that. It checks internally if the current thread holds the loading lock, and if so, it checks the key it wants to load. If it is the same as during the previous call, the exception is thrown. Now, let's assume the loader is async. What would that mean? Well, the coroutine may yield during loading (e.g. when performing an HTTP request to fetch the data) and the host thread will merrily move along and pick up the next coroutine. It still holds the lock, however. This has two fatal consequences:

  • when our loader finishes, there is no guarantee that it will be exe cuted by the same thread which holds the appropriate lock.
  • the thread which holds the lock may host a coroutine which may query the same missing key. Guava will throw an exception here, thinking that it is dealing with recursive load calls to the same key, when in reality that is not the case.

Using coroutines in an environment which isn't specifically crafted for them (read: 99.9% of all JVM libraries in existence) means opening pandoras box. This is precisely what the fancy presentations will not tell you. And the reason why I refactored a lot of code to eliminate coroutines entirely. I've never looked back.

Either you revert it, or you adapt your code to cope with new paradigms. As outlined, this should be easy to fix for the guava developers. In the meantime, a possible workaround is to wrap your loading functions inside a runBlocking scope. According to the docs:

runBlocking is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests.

In fact, I believe that Kotlin enables a more gradual transition to coroutines than building coroutines into the JVM. Adding a few Kotlin coroutines might be easier than switching a myriad of libraries to a new JVM version.

Code of Conduct Report abuse