https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
c

coletz

12/12/2018, 9:52 PM
Hi guys. I'm going crazy with some code. I have 2 mpp, one I manually created like 2 months ago and one created with "new>project>kotlin mpp (ios/android)". The first one is working fine, while the second one is throwing an error on ios (
kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen <object>@839b6268
). The whole code is the same. Anyone ever had similar issue?
👍 1
common code:
Copy code
internal expect val ApplicationDispatcher: CoroutineDispatcher

class PokeApi {

    private val httpClient = HttpClient()

    fun getPokemonList(success: (PokemonList) -> Unit){
        GlobalScope.launch(ApplicationDispatcher){
            val json: String = httpClient.get {
                url("<https://pokeapi.co/api/v2/pokemon/>")
            }
            val deferred = GlobalScope.async(ApplicationDispatcher) {
                JSON.nonstrict.parse(PokemonList.serializer(), json)
            }
            success(deferred.await())
        }
    }
}

@Serializable
data class Pokemon(
    val name: String,
    val url: String
)

@Serializable
data class PokemonList(
    val count: Int,
    val results: List<Pokemon>
)
t

thevery

12/12/2018, 10:46 PM
Try to freeze all the lambdas, e.g. http client callback
Recent KN releases are more strict on this, I've encountered similar issue
p

pandawarrior

12/13/2018, 3:24 AM
Any solution for it yet? I believe it’s the same issue with mine on iOS
mutation attempt of frozen <object>@c4226468
Copy code
private val client = HttpClient()

    fun callSimpleApi() {
        try {
            launch {
                getToolString()
            }
        } catch (e: Exception) {
            sampleView.returnString(e.toString())
        }
    }

    suspend fun getToolString() = client.get<String> {
        url("<https://tools.ietf.org/rfc/rfc1866.txt>")
    }
s

Sabrina Namur

12/13/2018, 6:54 AM
I'm not sure, because you said both projects have the same code, but I got this problem with kotlin 1.3.11. With kotlin 1.3.10 everything works fine.
👍 2
p

pandawarrior

12/13/2018, 7:57 AM
Oh really? let me check with kotlin 1.3.10.
@Sabrina Namur You are right, 1.3.11 is the problem. Thanks!
c

coletz

12/13/2018, 8:32 AM
Oh, the code was the same but I had different kotlin version... Thanks! But I'd like to know how to freeze lambda... Can you provide an example @thevery?
👍 1
t

thevery

12/13/2018, 8:37 AM
Sure. Non-frozen:
listOf(1, 2, 3).filter { it: Int -> it % 2 == 0 }
Frozen:
listOf(1, 2, 3).filter({ it: Int -> it % 2 == 0 }.freeze())
👍 1
c

coletz

12/13/2018, 8:55 AM
Actually it's not possible to freeze on common code, right? One should call freeze on the iOS code, or I'm missing something?
t

thevery

12/13/2018, 9:34 AM
I freeze on iOS side, in common you can create expect/actual or use https://github.com/touchlab/Stately
c

coletz

12/13/2018, 9:58 AM
so stately is just defining empty expect for other platforms (eg android) in order to use freeze and other stuff on common code... Basically what I've just done, but I can't get how I should call .freeze() on the code I provided before. You said to freeze httpclient's lambda callback, but these are builders and not a lambda called on call completed. That's a coroutine so there's no callback. Sorry if this sound stupid 😅
t

thevery

12/13/2018, 10:00 AM
ic. Can you try to log every line to get the actual crash reason?
c

coletz

12/13/2018, 10:03 AM
yep!
Copy code
class PokeApi {

    private val httpClient = HttpClient()

    fun getPokemonList(success: (PokemonList) -> Unit){
        1.log()
        GlobalScope.launch(ApplicationDispatcher){
            2.log()
            val json: String = httpClient.get {
                3.log()
                url("<https://pokeapi.co/api/v2/pokemon/>")
                4.log()
            }
            5.log()
            val deferred = GlobalScope.async(ApplicationDispatcher) {
                6.log()
                JSON.nonstrict.parse(PokemonList.serializer(), json)
            }
            7.log()
            success(deferred.await())
            8.log()
        }
    }
}

fun Int.log(){
    println("========= $this")
}
the crash is after log number 4
t

thevery

12/13/2018, 10:18 AM
Looks like freeze is needed in ktor itself, @e5l do you know about this issue?
e

e5l

12/13/2018, 10:27 AM
Yep, WIP. The fix would be available in the next minor release.
👍 2
p

Patrick Jackson

03/13/2019, 5:19 PM
Is this resolved now? Getting same exception with ktor 1.1.3 kotlin 1.3.21 coroutine 1.1.1
e

e5l

03/14/2019, 8:16 AM
Nope, still [WIP] 😞. You could fix the exception by preventing
client
instance freeze(do not create it in global scope or
object
singleton)
c

coletz

03/19/2019, 11:04 AM
So it seems like KT-30454 is by design and nothing is "really" broken... That means we will need to always instantiate a new client every time. From your knowledge is it possible to instantiate the client inside something like a view model and use it multiple times or this will still crash?
e

e5l

03/19/2019, 11:06 AM
Yes, and we testing the fix.
🙏 1