Generate UUID on kotlin-multiplatform? - kotlin

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

Related

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

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.

Why cannot be `const val` used in build.gradle.kts

I'd like to define a version constant in guild.gradle.kts file so that it can be used even in the plugins block. The plugins block requires restricted syntax:
«plugin version» must be constant, literal, strings
Following the restriction I tried to define the a version constant:
const val kotlinVersion = "1.3.72"
plugins {
java
kotlin("jvm") version kotlinVersion
}
However this fails with message
Const 'val' are only allowed on top level or in objects
even though the declaration seem to meet all const requirements. Why cannot be const val used in build.gradle.kts?
Even though it seems like your build script is top level, it isn't. The gradle docs mentions this when explaining the lifecycle of the build:
Finally, evaluate each Project by executing its build.gradle file, if present, against the project.
(source) This means that in your kotlin build scripts, the receiver type (i.e. this) is KotlinBuildScript which is eventually a subclass of Project. I don't know the details about how it's evaluated, but I can imagine it would be equivalent to what you can do in Kotlin with receiver types:
fun Project.evaluate(buildScript: Project.() -> Unit) = this.evaluate()
So your build script is really just the inside of a closure, hence why you can't use const val.

Type-Safe-Builder eval in Kotlin Native

I am experimenting a bit with Type Safe Builders in Kotlin. Now I have gotten the HML example to output by using the following.
val dsl = File("example.kts").readText()
val manager = ScriptEngineManager()
val engine = manager.getEngineByExtension("kts")
val html = engine.eval(dsl).toString()
Is this the right approach at all for running this from Kotlin?
If so, is there a way to make this work in Kotlin Multiplatform/Native, specifically when combining with Objective-C? (The ScriptEngine comes from a JVM dependency).
If not, what is the right way?

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.

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.