JetBrains / kotlin-native

Kotlin/Native infrastructure
Apache License 2.0
7.02k stars 568 forks source link

IncorrectDereferenceException without using top level variables #2443

Closed Coneys closed 3 years ago

Coneys commented 5 years ago

I was trying to use Kotlin/Native to share data models between iOS and Android app, but when I use my models from Swift, accesing it throws IncorrectDereferenceException: DispatchQueue.global(qos: .background).async { let mem = Mem(id: 0, sequence: 0, text: "test", text_x: 0.5, text_y: 0.5) DispatchQueue.main.async { print("Text: \(mem.text)") } }

I know that I can freeze my variable, but I have to change it sometime later. How can I pass thread ownership of this object? I know this is possible by Kotlin/Native Workers, but can I do it with iOS Queue?

olonho commented 5 years ago

There's not much difference here. See https://github.com/JetBrains/kotlin-native/blob/328413337b9dcab1dba6dd4d3cf5975d617e60d1/samples/objc/src/objcMain/kotlin/Window.kt#L20 - in this example we pass an object created with producer, and as result it's guaranteed to not have other references. Other approach is to use smth like code below, but wrapping boxed object like in sample above.


class Box<T>(boxed: T) {
    private var value_: T? = boxed
    val value: T get() {
        val result = value_!!
        value_ = null
        return result
    }
}

inline fun <reified T, reified R> Worker.executeAsync(data: Box<T>, crossinline consumerMaker: () -> ((T) -> R)): Future<R> =
        execute(TransferMode.SAFE, {
        Pair(data.value, consumerMaker())
    }) { it -> it.second(it.first) }

fun main() {
    val worker = Worker.start()
    val boxedInput = { Box(Input(42)) } ()
    val future = worker.executeAsync(boxedInput) { { input: Input ->
        input.int++
        input
    } }
    println(future.result)
}
Coneys commented 5 years ago

Thanks for your response. I tried example with Boxing, but the case is, I need to use concurrency in Swift (DispatchQueue) and I have no idea how to connect it with passing ownership. You did this using Worker api inside of Kotlin, which does it for you, right? With TransferMode.

I've read that I can do it manually using DetachedObjectGraph, is this right? Swift cannot see this class, so I did implement it with using expected and actual keywords. Then I created DetachedObjectGraph on background thread, but when I tried to receive value from it on main thread with attach() method, code threw IncorrectDereferenceException

nbransby commented 5 years ago

Sharing simple models between android and iOS seems like a fairly basic use case - if a developer chose not to use kotlin native and write their models twice, in swift and kotlin, then they could use them from any thread they like.

It seems strange that this appears to be overly complicated when using kotlin native. Feels like a barrier to entry to sharing code across platforms. Is there anyway to make it "just work" like native code?

olonho commented 5 years ago

Not with the current concurrency model, however we are evaluating possibilities of adding more options here.

rawadhilal88 commented 5 years ago

Adding more concurrency model options would be great. This is currently blocking us from using Kotlin for iOS. Our use cases work for Kotlin JVM/Android and Kotlin JS. Until there's an easy way of sharing mutable objects between threads on iOS we cannot support Kotlin native. Our customers heavily use the iOS dispatch queue and we can't limit them because we simply decided to use Kotlin to build our SDKs.

Reedyuk commented 5 years ago

Is there any update on when this might be changed? It's an absolute blocker for me.

Coneys commented 5 years ago

Same here, we would love to share code between iOS and Android, but for now it is too expensive (in time measure). It is faster to write code twice ;(

nbransby commented 5 years ago

August now and still no word on "evaluating possibilities of adding more options here"?

soundbites commented 5 years ago

We are having the same issue, but all our state is immutable. So a read only object accessible in Swift background threads would work as well.

kar commented 4 years ago

What I'm trying to do is to execute a function on another (non main) thread in iOS. No mutable state. Could someone give a basic example on how to do so?

SvyatoslavScherbina commented 3 years ago

About our plans: https://blog.jetbrains.com/kotlin/2020/07/kotlin-native-memory-management-roadmap/ YouTrack issue: https://youtrack.jetbrains.com/issue/KT-42296

There are a lot of articles and discussions in the internet. For example, see the topic in KMM documentation: https://kotlinlang.org/docs/mobile/concurrency-overview.html. Also there is public Kotlin Slack (visit http://slack.kotlinlang.org/ if you don't have access yet), channels #kotlin-native and #multiplatform are relevant.

Asking for help here, in this issue, is generally inefficient.