Remove import when using Kotlin's #Deprecated "ReplaceWith" annotation - kotlin

I have a custom function MutableStateFlow.update(), which i want to deprecate in favor of the official "kotlinx.coroutines.flow.update" version.
#Deprecated(
message = "This is not thread safe. Use the official version from kotlinx.coroutines.flow.update",
ReplaceWith("update(transformation)", "kotlinx.coroutines.flow.update"),
DeprecationLevel.ERROR
)
public inline fun <T> MutableStateFlow<T>.update(transformation: (previousValue: T) -> T) {
value = transformation(value)
}
This works ok-ish:
The main issue is that the signature of the old & the new fun are the same, so the IDE gets confused which to choose, since both are imported.
I therefore need to remove the import for my old version when the ReplaceWith is called. Is this possible? (Is there a better alternative?)
In case it matters: We're working mainly with Android Studio

If this is all in one open project, you could Refactor->Rename your update function (Shift + F6) to some unique name. Then there won't be the import conflict.

Related

Does the kotlin REPL have code completion?

I just opened kotlinc (which apparently defaults to kotlin-jvm ?) and dropped in some hello-world type code:
data class Person(val name: String, val age: Int) {
val isAdult get() = age >= 20
}
Let's create an instance :
val p = Person("ab", 10)
Hopefully the repl will offer us the properties via tab key .. ?
p.<tab>
The repl beeps on each tab instead of offering the properties of that Person instance. "Just in case" I :quit and opened kotlinc-jvm explicitly - and got the same behavior. Is it to be believed that there were no code completion available? Am I missing some option to starting kotlinc ?
Update: JetBrains has now released ki, which supports auto completion (and more).
The kotlin repl currently does not support tab completion. See the official bug tracker for more details:
https://youtrack.jetbrains.com/issue/KT-14177,
https://youtrack.jetbrains.com/issue/KT-23036
If you use IntelliJ, you may want to try out scratch files. They work well for small bits of code and support code completion.
Intellij Kotlin-REPL does have code completion. It makes a ton of sense to use the IDE coming from the creators of the language JetBrains.

Generate UUID on kotlin-multiplatform?

Are there any kotlin-multiplatform common functions to get a UUID/GUID?
// ideally something like this
val newUUID = UUID() // "1598044e-5259-11e9-8647-d663bd873d93"
println("newUUID = $newUUID")
I'd prefer not to make separate Android and iOS versions using expect-actual.
As per the Kotlin multiplatform documentation, you can make an expect/actual function to use the Android (java) and iOS (NSUUID) specific implementations:
// Common
expect fun randomUUID(): String
// Android
import java.util.*
actual fun randomUUID() = UUID.randomUUID().toString()
// iOS
import platform.Foundation.NSUUID
actual fun randomUUID(): String = NSUUID().UUIDString()
That one may work
https://github.com/benasher44/uuid
The sources of the project use the Kotlin Multiplatform project to implement the UUID library. See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html for more details

Annotation class does not validate input as enum in Kotlin

I'd like to create annotation instead of enum use it for when statement
#Retention(AnnotationRetention.SOURCE)
#IntDef(SELECT.toLong(), WEAR.toLong(), BAND.toLong())
annotation class CurrentState
companion object {
const val SELECT = 0
const val WEAR = 1
const val BAND = 2
}
private fun handleFragment(#CurrentState state:Int) {
val fragment:Fragment =
when(state){
SELECT -> SelectDeviceFragment.newInstance()
WEAR -> ConnectWatchFragment.newInstance()
BAND -> SelectDeviceFragment.newInstance()
}
From my understanding, this code should prevent me from performing following code:
handleFragment(5)
and when statement should not ask me to add else statement, as expected from enum
What I'm doing wrong or misunderstand?
From https://discuss.kotlinlang.org/t/intdef-and-stringdef-not-being-checked-at-compile-time/7029:
This checking doesn’t come from the compiler, but from Android lint. Work to make android lint language independent is being done, but if I’m not mistaken you’ll need a newer version of Android Studio for it.
And Android Studio 3.1 blog post mentions lint checks for Kotlin as a feature (though it doesn't say whether this check specifically is supported).
The #IntDef annotation is part of the Android framework. The compiler is not aware of any specific semantics of this annotation, and is not able to use it for checking the exhaustiveness of when statements.
Moreover, even with the annotation, you can call handleFragment(5). Such code will not be a compiler error, it will only be reported as a lint warning.

Extension function collision [duplicate]

If I have a jar, on the classpath, where I've created an extension function on say the String class for argument's sake and I have another jar with the same extension function on String, how will Kotlin resolve the two?
I presume if both functions are defined in the same packages then there will be a clash?
But if different packages, how I can distinguish the two extensions?
Indeed, if they're in the same package, it won't compile. For the other scenario, let's say you have two files with two different packages, containing extension functions with the same signature:
First file:
package ext1
fun Int.print() = print(this)
Second file:
package ext2
fun Int.print() = print(this * 2)
And this file where you're trying to use it:
package main
fun main(args: Array<String>) {
42.print()
}
IntelliJ will actually give you an import dialog where you can choose which one you want to use:
You can import one of them like this:
import ext1.print
And if you need to use the other one as well, you can rename it with the as keyword. This keyword works for imports in general, classes with the same name, etc.
import ext2.print as print2
So this program compiles and prints 4284:
package main
import ext1.print
import ext2.print as print2
fun main(args: Array<String>) {
42.print()
42.print2()
}
As a quick note, the one you import with the as keyword will be slightly harder to use, as autocomplete doesn't seem to pick it up well, selecting the second option here just completes the call to 42.print().
So since extension function in kotlin is just static function, other functions will be distinguish by import.
Also you can make alias for one of extension functions for more readability:
import by.bkug.extensions.helpers.extension
import by.bkug.extensions.extension as extension1
fun test() {
myType().extension() // by.bkug.extensions.helpers.extension
myType().extention1() // by.bkug.extensions.extension
}

Jinq in Kotlin - how to convert lambda into java SerializedLambda?

Can I have serializable lambda in Kotlin? I am trying to use Jinq library from Kotlin, but it requires serializable lambdas. Is there any syntax that makes it possible?
Update:
My code:
var temp=anyDao.streamAll(Task::class.java)
.where<Exception,Task> { t->t.taskStatus== TaskStatus.accepted }
.collect(Collectors.toList<Task>());
I am getting this error:
Caused by: java.lang.IllegalArgumentException:
Could not extract code from lambda.
This error sometimes occurs because your lambda references objects that aren't Serializable.
All objects referenced in lambda are serializable (code results in no errors in java).
Update 2
After debugging it seems that kotlin lambda isn't translated into java.lang.invoke.SerializedLambda which is required by Jinq to get information from. So the problem is how to convert it to SerializedLambda.
I'm the maker of Jinq. I haven't had the time to look at Kotlin-support, but based on your description, I'm assuming that Kotlin compiles its lambdas into actual classes or something else. As such, Jinq would probably need some special code for cracking open Kotlin lambdas, and it may also need special code for handling any unusual Kotlin-isms in the generated code. Jinq should be capable of handling it because it was previously retrofitted to handle Scala lambdas.
If you file an issue in the Jinq github about it, along with a small Kotlin example (in both source and .class file form), then I can take a quick peek at what might be involved. If it's small, I can make those changes. Unfortunately, if it looks like a lot of work, I don't think I can really justify putting a lot of resources into adding Kotlin support to Jinq.
I have no experience on Jinq, but according to the implementation in GitHub and my experience of using Java Library in Kotlin.
ref: https://github.com/my2iu/Jinq/blob/master/api/src/org/jinq/orm/stream/JinqStream.java
You can always fall back to use the native Java Interface in Kotlin.
var temp = anyDao.streamAll(Task::class.java)
.where( JinqStream.Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
// Alternatively, You you can import the interface first
import org.jinq.orm.stream.JinqStream.*
...
// then you can use Where instead of JinqStream.Where
var temp = anyDao.streamAll(Task::class.java)
.where(Where<Task,Exception> { t -> t.taskStatus == TaskStatus.accepted } )
.collect(Collectors.toList<Task>());
Or make a custom extension to wrap the implementation
fun JinqStream<T>.where(f: (T) -> Boolean): JinqStream<T> {
return this.where(JinqStream.Where<T,Exception> { f(it) })
}
Disclaimer: The above codes have not been tested.