Feedback wanted: Migration to stable coroutines in Kotlin 1.3

As announced in Kotlin 1.3-M1 blog post coroutines are graduating and are becoming a stable feature in Kotlin 1.3. Migration to the graduated coroutines would require removing experimental from all the package names as well as adjustments to the usages of certain low-level APIs like Continuation and advanced functions from intrinsics package.

We are releasing an updated version of all JetBrains libraries like kotlinx.coroutines for graduated coroutines. However, if you happen to be using 3rd party library that exposes experimental coroutines in its APIs and the maintainers of that library would not perform a timely update to the Kotlin 1.3 graduated coroutines, then you’ll find that you cannot use the functions in those libraries that expose experimental coroutines if your project is configured with Kotlin language level 1.3 — Kotlin compiler will report an error on an attempt to use them.

Hereby we are gathering feedback to decide on what kind of support we would need to provide for that scenario in Kotlin 1.3 release. Please, respond if you are using any 3rd party non-JetBrains libraries that you do not control and which expose experimental Kotlin coroutines in their APIs. We are interested to know what libraries are those and how exactly the experimental coroutines are exposed by those libraries:

  1. They expose suspend functions.
  2. They receive or return suspend functional types.
  3. They receive, return or otherwise expose types from kotlinx.coroutines.experimental package and thus would prevent you from fully migrating to the version of kotlinx.coroutines library for Kotlin 1.3 which removes experimental from all the package names.

Links to your applications and the corresponding libraries’ code (if possible, of course) would be extremely helpful.

Please, feel free to comment if you feel that you would be otherwise inconvenienced by inability to use code that was compiled with Kotlin language level 1.2 and exposes experimental coroutines from the code that is being compiled with Kotlin language level 1.3.

For android the most popular are:

We use vertx-lang-kotlin-coroutines:

It exposes suspend functions and functions returning Channel

3 Likes

On Android I’m using Fuel’s coroutines:

Well, I have a super-tiny library which probably noone uses except me :yum:, but don’t worry … as soon as the new Kotlin is out, I will flip it to 1.3 :wink:. Which keeps me thinking that due to backward incompatibility I will have to jump from version 0.0.1 straight to the 0.1.0 :grin:. Anyway if you need any analysis, it is here: GitHub - LittleLightCz/Krool: Kotlin resource pool based on non-blocking coroutines. Useful for sharing expensive resources in a concurrent environment.

kotlin-coroutines-retrofit now available also for Kotlin 1.3 in version 0.12.0-eap13

1 Like

Here are some coroutines libraries I use:

BleScanCoroutines:

This an Android library that transforms callback based Bluetooth Low Energy scanning to a ReceiveChannel.

  • A public constructor takes a CoroutineContext which defaults to CommonPool.
  • A public method returns a ReceiveChannel.
  • All the code is in an experimental sub-package.

Note that I am the maintainer of this library.

BleGattCoroutines:

This is an Android library that transforms callback hell based Bluetooth Low Energy connection and communication to suspending functions.

  • A ConflatedBroadcastChannel is exposed (although it’s likely to get deprecated in the next version).
  • A ReceiveChannel is exposed.
  • Many public suspend functions are exposed.
  • All the code is in an experimental sub-package.

Note that I am the maintainer of this library.

CameraCoroutines:

This is an Android library that transforms callback hell based Camera2 API to a kind of suspending DSL.

It is currently work in progress. The sample can already record videos properly, but there’s still work to do to support all of the Camera2 API, including API 28 additions (upcoming Android P with multi-camera support).

I’m also the maintainer of this library, but I only use it in the sample at the moment, I copy pasted it as a library module in the project where I needed it, and I’ll replace it manually when the library is ready.

It is not released on jcenter at the moment.

I just noticed I forgot to add all the code into an experimental sub-package. Now that coroutines graduation is coming, and that you ask for feedback for migration, without giving much information about how it’ll happen really, I feel seriously lost about how I should manage it. And soon to be deprecated Android support libraries vs not API stable yet AndroidX/Jetpack migration makes me a bit more lost on what is the right way to publish a library that uses both. I also wonder if there’s any link between “Jetifier” and the tooling you may provide for Kotlin coroutines and kotlinx.coroutines migration.

Splitties preferences:

This is an Android library bringing property syntax for Android shared preferences.

The preferences module has an optional dependency to org.jetbrains.kotlinx:kotlinx-coroutines-android (compileOnly).

It provides an abstract class named SuspendPrefsAccessor (which is in an experimental sub-package) that is made to be extended by the companion object of the Preferences subclasses. Its constructor takes a CoroutineDispatcher parameter and the class provides a suspend operator fun invoke().

Here’s a usage example in the sample.

Note that I am the maintainer of this library, as you probably guessed from my pseudo matching the repo owner.

kotlin-coroutines-retrofit:

  • Exposes public suspend extension functions.

retrofit2-kotlin-coroutines-adapter:

This library does not really expose any suspend related functions, only the implementation deals with the Deferred type. Migration for this library is very simple, you just have to change the artifact name and version, dropping the experimental word in the dependency identifier, and voilà, the package didn’t change, and no suspend or coroutines related types were part of the public API.

The fact that this library didn’t follow the recommendations for experimental coroutines and experimental kotlinx.coroutines usage, yet has a migration that is currently easier than for kotlinx.coroutines itself leaves me wondering about what I should do as the maintainer of 4 libraries that rely on these graduating experimental features, plus several projects using these libraries. *I feel the need for some guidance to do it right.

IIRC, it has both kinds.

I am writin a lib: GitHub - jasync-sql/jasync-sql: Java & Kotlin Async DataBase Driver for MySQL and PostgreSQL written in Kotlin and just started to use coroutines internal (not in exposed api). Since this is new I am not using experimental packages. I wonder how this affects lib users? They will not be able to use it if they are using experimental coroutines?

DBflow is using it.

Hi.
Sorry if it may sound a bit petty.
First, Kotlin 1.3 Coroutines bring great and essential goodies, and is a blessed step with the scopes.
However, for 90% of the cases, the default behaviour is just fine for me.
Unfortunately, even with the default, launch methods becomes a bit too verbose, in my most humble opinion. At least in the stage of migrating, before using that new power for fine-tuning.

Instead of launch(UI) {} it’s now GlobalScope.launch(Dispatchers.Main) {}
While it’s very important to have scope encapsulation, it somehow feels “long”.

I have created some CoroutineExt file that just defines global funcs to alias it.
I know, my fingers deserve a lashing, and I ought not to do that, still… I do want my code to be short and nice.

Is there any shorter way of keeping coroutine launchers short, using a default? Am I missing anything?

Thanks

I am right in process of migration of large project to stable coroutines. The indeed became more verbose, which is not in fact bad. One can always write a few extensions to fix that. New coroutines use the context-oriented approach extensively which is good in my opinion (please do not forget to vote for KT-10468).

The problem I’ve encountered is more complicated management of job structure. Until 1.0, I just created some empty jobs and assigned them to child coroutines as parentJob = job. Now it seems, that I have multiple control handlers: I can use the scope itself, then I can pass additional CoroutineContext to new coroutine and Job itself is a context. So I can write something like scope.launch(job){...}, but it is not that clear, who controls the job execution, the job I passed, or the scope. I think that some additional documentation and/or safe extensions are in order.

1 Like

Agree, the purpose of separating to scopes is not just “right”, I would use the word “sacred”.
I have seen bad code where using global executor goes wrong, and it has no happy end :wink:

Somehow, I do feel unease when adding extensions. When it’s dictated by the gods of the platform, it’s okay, it’s universal, but when I define extensions - I have that nagging feeling that somebody might stumble on it one day.

Yeah, encountered that issue that you mention, too.
I got some “subsystem”. I would like to create a thread autonomy for that portion of code.
I find it tedious to manage both context, scope, jobs etc, and shut them down safely. E.g. when logging out.

P.S: As for KT-10468: I am too conservative. I am afraid that it is not clear (in 1sec of reading) that the “dp” extension comes in context of a View and is invalid without it. Some day, when you look at a remote corder of your code, you may wonder where that “dp” comes from, and why it doesn’t work when just evaluating it with Alt-F8. Sorry, I’m too :chicken: chicken to vote up for it.