Search code examples
iosswiftkotlinkotlin-multiplatformkotlin-native

Unable to pass swift implementation of kotlin interface to kotlin native


I have an interface SampleInterface in CommonMain

interface SampleInterface {
  fun printMessage(message: String)
}

and a singleton object Singleton in CommonMain

object Singleton {
  private var interfaceObj: SampleInterface? = null
  fun setup(interfaceObj: SampleInterface) {
    this.interfaceObj = interfaceObj
  }

  fun printMessage(message: String) {
    this.interfaceObj?.printMessage(message)
  }
}

I am trying to Implement the interface SampleInterface in swift

class IosImpl: SampleInterface {
  func printMessage(message: String) {
    print("\(message)")
  }
}

passing the IosImpl object from swift to Singleton in kotlin native

func test() {
  let iImpl = IosImpl()
  Singleton().setup(iImpl) // Failing with KotlinException
}

Exception:

Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen 

Solution

  • The problem here is the result of trying to mutate Kotlin's singleton.
    In Kotlin/Native, there are strict immutability rules, and one of them states that every object is mutable XOR shared. To achieve this, for singleton objects and enums are "frozen" by default - this means every attempt to mutate them will finish with InvalidMutabilityException, as you got. To avoid this, one got to make sure that object is thread-local and will never be mutated from another thread.
    To read more on this theme, I recommend you to take a look at Immutability description on the K/N Github, and also the Concurrency one.