<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Russell Wolf</title>
    <description>The latest articles on DEV Community by Russell Wolf (@russhwolf).</description>
    <link>https://dev.to/russhwolf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F345942%2F61caa65b-9fa6-4444-bc37-3df012af0ecb.png</url>
      <title>DEV Community: Russell Wolf</title>
      <link>https://dev.to/russhwolf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/russhwolf"/>
    <language>en</language>
    <item>
      <title>Multiplatform Settings 1.0.0</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Sun, 15 Jan 2023 03:12:17 +0000</pubDate>
      <link>https://dev.to/russhwolf/multiplatform-settings-100-5eoa</link>
      <guid>https://dev.to/russhwolf/multiplatform-settings-100-5eoa</guid>
      <description>&lt;p&gt;Today, I've released version 1.0.0 of Multiplatform Settings.  That means I'm committed to maintaining the current API surface of everything not marked as experimental until there's a 2.0 release (which I don't currently have plans for). If you need to save simple, unstructured key-value data in your multiplatform apps, I hope you'll consider using it. A lot of you already are!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/russhwolf" rel="noopener noreferrer"&gt;
        russhwolf
      &lt;/a&gt; / &lt;a href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;
        multiplatform-settings
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Kotlin Multiplatform library for saving simple key-value data
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-linux.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d6e19ef5b5ab027381ef5089eb63cbab7e2addc58435a6b725e41bd0f4fe6bb4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d6c696e75782e796d6c3f6272616e63683d6d61696e266c6162656c3d4a564d2532464a53253246416e64726f69642532464c696e75782532304275696c64266c6f676f3d4c696e7578266c6f676f436f6c6f723d626c61636b" alt="Linux Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-macos.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/080e1ed8db29d4a76f5db83b49da2e4025d71228582df97eac047b297aa61f9c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d6d61636f732e796d6c3f6272616e63683d6d61696e266c6162656c3d694f532532466d61634f5325324674764f5325324677617463684f532532304275696c64266c6f676f3d4170706c65" alt="Mac Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-windows.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/456e350c9354c64723b3368448128b57c9cb0f06b4f5810e126189d549a4cc30/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d77696e646f77732e796d6c3f6272616e63683d6d61696e266c6162656c3d57696e646f77732532304275696c64266c6f676f3d57696e646f7773" alt="Windows Build Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://search.maven.org/artifact/com.russhwolf/multiplatform-settings" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af0e93de3d85e76090862454976c76f502c7a90e7837ffd0f61558c81e5c0bf5/68747470733a2f2f696d672e736869656c64732e696f2f6d6176656e2d63656e7472616c2f762f636f6d2e7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67733f6c6162656c3d4d6176656e25323043656e7472616c" alt="Maven Central"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Multiplatform Settings&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This is a Kotlin library for Multiplatform apps, so that common code can persist key-value data.&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://github.com/wooram-yang/multiplatform-settings/blob/feature/add_ko_readme_file/README-ko.md" rel="noopener noreferrer"&gt;Korean translation&lt;/a&gt;
of this readme is available separately, maintained by @wooram-yang&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#implementation-summary" rel="noopener noreferrer"&gt;Implementation Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#creating-a-settings-instance" rel="noopener noreferrer"&gt;Creating a Settings instance&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#platform-constructors" rel="noopener noreferrer"&gt;Platform constructors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#factories" rel="noopener noreferrer"&gt;Factories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#no-arg-module" rel="noopener noreferrer"&gt;No-arg module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#settings-api" rel="noopener noreferrer"&gt;Settings API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#listeners" rel="noopener noreferrer"&gt;Listeners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#testing" rel="noopener noreferrer"&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#other-platforms" rel="noopener noreferrer"&gt;Other platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#experimental-api" rel="noopener noreferrer"&gt;Experimental API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#experimental-implementations" rel="noopener noreferrer"&gt;Experimental Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#serialization-module" rel="noopener noreferrer"&gt;Serialization module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#coroutine-apis" rel="noopener noreferrer"&gt;Coroutine APIs&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#datastore" rel="noopener noreferrer"&gt;DataStore&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#make-observable-module" rel="noopener noreferrer"&gt;Make-Observable module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#adding-to-your-project" rel="noopener noreferrer"&gt;Adding to your project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#building" rel="noopener noreferrer"&gt;Building&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Settings&lt;/code&gt; interface has implementations on the Android, iOS, macOS, watchOS, tvOS, JS, WasmJS, JVM, and Windows
platforms.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Implementation Summary&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The following table shows the names of implementing classes and what platforms they're available on.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Backing API&lt;/th&gt;
&lt;th&gt;Platforms&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;KeychainSettings&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Apple Keychain&lt;/td&gt;
&lt;td&gt;iOS, macOS, watchOS, tvOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;NSUserDefaultsSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;User Defaults&lt;/td&gt;
&lt;td&gt;iOS, macOS, watchOS, tvOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PreferencesSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;java.util.prefs.Preferences&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PropertiesSettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;java.util.Properties&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SharedPreferencesSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;android.content.SharedPreferences&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;StorageSettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Web Storage (localStorage)&lt;/td&gt;
&lt;td&gt;JS, WasmJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;RegistrySettings&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Windows Registry&lt;/td&gt;
&lt;td&gt;MingwX64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;DataStoreSettings&lt;/code&gt;&lt;sup&gt;3&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;androidx.datastore.core.DataStore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android,&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Some History
&lt;/h2&gt;

&lt;p&gt;Multiplatform Settings was one of the first Kotlin Multiplatform libraries ever released, with the first version published on May 28, 2018. I called that first version 0.1-alpha, though I would later drop the alpha from the versioning scheme as it's somewhat redundant with 0.x. At the time I always imagined that I would call the library 0.x until the overall Multiplatform tooling was labelled as stable, but that's been a longer process than I originally expected. Now that Kotlin Multiplatform Mobile is officially in Beta and we're seeing a big uptick in interest and usage in the community, this seems like a good moment for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;As I detailed in my &lt;a href="https://dev.to/russhwolf/looking-toward-multiplatform-settings-100-10aa"&gt;last post&lt;/a&gt;, there are a couple things still marked as experimental in this first stable release, and without committing to any specific timeline, I'd like to stabilize them in the near future. If you're a user of &lt;code&gt;KeychainSettings&lt;/code&gt;, &lt;code&gt;RegistrySettings&lt;/code&gt;, &lt;code&gt;multiplatform-settings-coroutines&lt;/code&gt;, or &lt;code&gt;multiplatform-settings-serialization&lt;/code&gt;, I'm very interested in hearing your feedback on how well they're working for you. Bug reports or issues you've had using these APIs are helpful for improving them, but so are reports that you've used them and they've worked well, because that's what tells me that they're ready for wider use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about DataStore?
&lt;/h2&gt;

&lt;p&gt;One thing that's new since I started planning this 1.0 release is that Google announced a preview multiplatform version of the DataStore library. This has a very similar use-case to Multiplatform Settings, so which should you use?&lt;/p&gt;

&lt;p&gt;One difference between these two libraries is, Multiplatform Settings focuses on interop with existing platform APIs, while DataStore is a brand new implementation. This means that if you have existing platform code using SharedPreferences, UserDefaults, web Storage, or any of the other platform APIs that Multiplatform Settings supports, you can continue to use that code and it will share its source of truth with your common code using Multiplatform Settings. &lt;/p&gt;

&lt;p&gt;If that interop is not a concern for you, then DataStore can also be a great choice. And with the &lt;code&gt;multiplatform-settings-coroutines&lt;/code&gt; and &lt;code&gt;multiplatform-settings-datastore&lt;/code&gt; modules, you can wrap DataStore in the Multiplatform Settings API, if you want use DataStore in some places and Multiplatform Settings in others. These modules are currently only available on Android and JVM, but I intend to release them on other platforms once the multiplatform DataStore becomes more stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks for reading
&lt;/h2&gt;

&lt;p&gt;It's an exciting time to be building things with Kotlin Multiplatform! I hope you find this first stable release of Multiplatform Settings helpful for your KMP projects. Let me know in the &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues" rel="noopener noreferrer"&gt;issues&lt;/a&gt; or &lt;a href="https://github.com/russhwolf/multiplatform-settings/discussions" rel="noopener noreferrer"&gt;discussions&lt;/a&gt; if you encounter any problems or have any other feedback.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
    </item>
    <item>
      <title>Looking toward Multiplatform Settings 1.0.0</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Mon, 25 Jul 2022 00:02:18 +0000</pubDate>
      <link>https://dev.to/russhwolf/looking-toward-multiplatform-settings-100-10aa</link>
      <guid>https://dev.to/russhwolf/looking-toward-multiplatform-settings-100-10aa</guid>
      <description>&lt;p&gt;The first version of Multiplatform Settings was released in May 2018. At that time I imagined I would leave it in some form of prerelease 0.x state until Kotlin/Native and Kotlin Multiplatform were fully stable. But it's been over four years now, and plenty of other libraries in the ecosystem have gone 1.0. With the Kotlin Multiplatform Mobile beta on the horizon, I've decided it's about time for Multiplatform Settings to have a stable release.&lt;/p&gt;

&lt;p&gt;In preparation for that, I recently released version &lt;code&gt;1.0.0-alpha01&lt;/code&gt;. This includes a number of breaking changes in order to make the API a bit more consistent and intuitive. I've done my best to provide migration aids in the form of &lt;code&gt;@Deprecated&lt;/code&gt; annotations which in most cases will allow users to update automatically. But if for some reason you're not ready to do that, version &lt;code&gt;0.9&lt;/code&gt; was also released recently with almost all the same functionality and none of the breakage.&lt;/p&gt;

&lt;p&gt;If you've never heard of Multiplatform Settings or you'd like to take a closer look, be sure check it out on Github!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/russhwolf" rel="noopener noreferrer"&gt;
        russhwolf
      &lt;/a&gt; / &lt;a href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;
        multiplatform-settings
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Kotlin Multiplatform library for saving simple key-value data
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-linux.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d6e19ef5b5ab027381ef5089eb63cbab7e2addc58435a6b725e41bd0f4fe6bb4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d6c696e75782e796d6c3f6272616e63683d6d61696e266c6162656c3d4a564d2532464a53253246416e64726f69642532464c696e75782532304275696c64266c6f676f3d4c696e7578266c6f676f436f6c6f723d626c61636b" alt="Linux Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-macos.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/080e1ed8db29d4a76f5db83b49da2e4025d71228582df97eac047b297aa61f9c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d6d61636f732e796d6c3f6272616e63683d6d61696e266c6162656c3d694f532532466d61634f5325324674764f5325324677617463684f532532304275696c64266c6f676f3d4170706c65" alt="Mac Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings/actions/workflows/build-windows.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/456e350c9354c64723b3368448128b57c9cb0f06b4f5810e126189d549a4cc30/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67732f6275696c642d77696e646f77732e796d6c3f6272616e63683d6d61696e266c6162656c3d57696e646f77732532304275696c64266c6f676f3d57696e646f7773" alt="Windows Build Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://search.maven.org/artifact/com.russhwolf/multiplatform-settings" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af0e93de3d85e76090862454976c76f502c7a90e7837ffd0f61558c81e5c0bf5/68747470733a2f2f696d672e736869656c64732e696f2f6d6176656e2d63656e7472616c2f762f636f6d2e7275737368776f6c662f6d756c7469706c6174666f726d2d73657474696e67733f6c6162656c3d4d6176656e25323043656e7472616c" alt="Maven Central"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Multiplatform Settings&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This is a Kotlin library for Multiplatform apps, so that common code can persist key-value data.&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://github.com/wooram-yang/multiplatform-settings/blob/feature/add_ko_readme_file/README-ko.md" rel="noopener noreferrer"&gt;Korean translation&lt;/a&gt;
of this readme is available separately, maintained by @wooram-yang&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#implementation-summary" rel="noopener noreferrer"&gt;Implementation Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#creating-a-settings-instance" rel="noopener noreferrer"&gt;Creating a Settings instance&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#platform-constructors" rel="noopener noreferrer"&gt;Platform constructors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#factories" rel="noopener noreferrer"&gt;Factories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#no-arg-module" rel="noopener noreferrer"&gt;No-arg module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#settings-api" rel="noopener noreferrer"&gt;Settings API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#listeners" rel="noopener noreferrer"&gt;Listeners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#testing" rel="noopener noreferrer"&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#other-platforms" rel="noopener noreferrer"&gt;Other platforms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#experimental-api" rel="noopener noreferrer"&gt;Experimental API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#experimental-implementations" rel="noopener noreferrer"&gt;Experimental Implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#serialization-module" rel="noopener noreferrer"&gt;Serialization module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/russhwolf/multiplatform-settings#coroutine-apis" rel="noopener noreferrer"&gt;Coroutine APIs&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#datastore" rel="noopener noreferrer"&gt;DataStore&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#make-observable-module" rel="noopener noreferrer"&gt;Make-Observable module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#adding-to-your-project" rel="noopener noreferrer"&gt;Adding to your project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#building" rel="noopener noreferrer"&gt;Building&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Settings&lt;/code&gt; interface has implementations on the Android, iOS, macOS, watchOS, tvOS, JS, WasmJS, JVM, and Windows
platforms.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Implementation Summary&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The following table shows the names of implementing classes and what platforms they're available on.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Backing API&lt;/th&gt;
&lt;th&gt;Platforms&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;KeychainSettings&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Apple Keychain&lt;/td&gt;
&lt;td&gt;iOS, macOS, watchOS, tvOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;NSUserDefaultsSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;User Defaults&lt;/td&gt;
&lt;td&gt;iOS, macOS, watchOS, tvOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PreferencesSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;java.util.prefs.Preferences&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PropertiesSettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;java.util.Properties&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SharedPreferencesSettings&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;android.content.SharedPreferences&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;StorageSettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Web Storage (localStorage)&lt;/td&gt;
&lt;td&gt;JS, WasmJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;RegistrySettings&lt;/code&gt;&lt;sup&gt;2&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;Windows Registry&lt;/td&gt;
&lt;td&gt;MingwX64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;DataStoreSettings&lt;/code&gt;&lt;sup&gt;3&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;androidx.datastore.core.DataStore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android,&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Breaking Changes
&lt;/h2&gt;

&lt;p&gt;Here's a quick tour of breaking changes and other updates so you know what to expect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation class renames
&lt;/h3&gt;

&lt;p&gt;In the early days, there was generally a single implementation of the &lt;code&gt;Settings&lt;/code&gt; class per platform, so I gave them names like &lt;code&gt;AndroidSettings&lt;/code&gt;, &lt;code&gt;AppleSettings&lt;/code&gt;, and &lt;code&gt;JsSettings&lt;/code&gt;. This naming scheme couldn't really hold as more implementations like &lt;code&gt;KeychainSettings&lt;/code&gt; and &lt;code&gt;DataStoreSettings&lt;/code&gt; were added. For the sake of consistency, for 1.0 the platform-based names are all being changed to mark the backing API that the implementation uses. The full list of renames is below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Old name&lt;/th&gt;
&lt;th&gt;New name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AndroidSettings&lt;/td&gt;
&lt;td&gt;SharedPreferencesSettings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppleSettings&lt;/td&gt;
&lt;td&gt;NSUserDefaultsSettings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JvmPreferencesSettings&lt;/td&gt;
&lt;td&gt;PreferencesSettings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JvmPropertiesSettings&lt;/td&gt;
&lt;td&gt;PropertiesSettings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WindowsSettings&lt;/td&gt;
&lt;td&gt;RegistrySettings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MockSettings&lt;/td&gt;
&lt;td&gt;MapSettings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Update listener changes
&lt;/h3&gt;

&lt;p&gt;The original &lt;code&gt;ObservableSettings&lt;/code&gt; interface was based around an untyped &lt;code&gt;addListener()&lt;/code&gt; function, with the consumer responsible for reading out the current value at the observed key when the listener was called. This was awkward to use, so  typed extension functions like &lt;code&gt;addIntListener()&lt;/code&gt; were added later to do this work for you, but the core API remained. However, I don't see much use-case for the untyped API, and it makes it more difficult to convert between &lt;code&gt;ObservableSettings&lt;/code&gt; and &lt;code&gt;FlowSettings&lt;/code&gt;, which only includes typed APIs. So for 1.0 the untyped &lt;code&gt;addListener()&lt;/code&gt; will be removed and the extension functions moved into the &lt;code&gt;ObserableSettings&lt;/code&gt; interface. &lt;/p&gt;

&lt;p&gt;If you maintain a custom &lt;code&gt;ObservableSettings&lt;/code&gt; implementation, the migration hopefully shouldn't be too bad because you can leave your untyped &lt;code&gt;addListener()&lt;/code&gt; as an internal implementation detail and just call it from the typed methods. This is also what most of the library classes are doing now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default values
&lt;/h3&gt;

&lt;p&gt;Going back to the very first release of the library, there are many places across the Multiplatform Settings API surface that take a &lt;code&gt;defaultValue&lt;/code&gt; parameter which is returned if the key in question isn't present. These &lt;code&gt;defaultValue&lt;/code&gt; parameters almost always have default parameter values, so you could call &lt;code&gt;settings.getInt("key")&lt;/code&gt; which would do the same as &lt;code&gt;settings.getInt("key", defaultValue = 0)&lt;/code&gt;. More recently, nullable getters were added so you can do things like &lt;code&gt;settings.getIntOrNull("key")&lt;/code&gt; which will return &lt;code&gt;null&lt;/code&gt; if &lt;code&gt;"key"&lt;/code&gt; isn't set. This makes for a slightly confusing API where you might be surprised that &lt;code&gt;getInt("key")&lt;/code&gt; returns &lt;code&gt;0&lt;/code&gt; instead of &lt;code&gt;null&lt;/code&gt;, so I've opted to remove the default parameter value from the non-nullable getters. This is slightly more verbose in the event that you wanted the library's default values but I think it makes for fewer surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing &lt;code&gt;multiplatform-settings-coroutines-native-mt&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When I first published the coroutines interop APIs, I created two separate modules in an attempt to accomodate people using both the mainline and &lt;code&gt;native-mt&lt;/code&gt; coroutines versions. With the new Kotlin/Native memory model on the horizon and understanding that the &lt;code&gt;native-mt&lt;/code&gt; branch of &lt;code&gt;kotlinx-coroutines&lt;/code&gt; will no longer be maintained, I removed the &lt;code&gt;multiplatform-settings-coroutines-native-mt&lt;/code&gt; module in &lt;code&gt;1.0.0-alpha01&lt;/code&gt;. If you were using it, you should migrate to &lt;code&gt;multiplatform-settings-coroutines&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing experimental markers
&lt;/h3&gt;

&lt;p&gt;Some, but not all, things that were previously marked as &lt;code&gt;@ExperimentalSettingsApi&lt;/code&gt; or &lt;code&gt;@ExperimentalSettingsImplementation&lt;/code&gt; are no longer annotated to indicate that they will be stable in 1.0. This includes the &lt;code&gt;ObservableSettings&lt;/code&gt; and &lt;code&gt;SettingsListener&lt;/code&gt; interfaces, and the &lt;code&gt;PreferencesSettings&lt;/code&gt; and &lt;code&gt;PropertiesSettings&lt;/code&gt; implementations. &lt;/p&gt;

&lt;p&gt;Some items remain experimental in 1.0 to indicate that they still aren't well-tested or to allow for the possibility of breaking changes in the future. These include the coroutine and serialization interop APIs, as well as &lt;code&gt;RegistrySettings&lt;/code&gt; on Windows and &lt;code&gt;KeychainSettings&lt;/code&gt; on Apple platforms. I'm eager for more feedback on all of these things so that they too can become stable, so please let me know what is and isn't working well for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The road ahead
&lt;/h2&gt;

&lt;p&gt;After the 1.0 release, the next goal will be stabilizing the APIs and implementations that are still experimental. You can help by providing feedback, fixing bugs, improving testing, or suggesting (and possibly helping implement) other changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coroutines integration
&lt;/h3&gt;

&lt;p&gt;For the &lt;code&gt;multiplatform-settings-coroutines&lt;/code&gt; APIs, I want to know if the introduction of &lt;code&gt;SuspendSettings&lt;/code&gt; and &lt;code&gt;FlowSettings&lt;/code&gt; is helpful. I worry a little that it's a lot of API to accomodate one implementation (&lt;code&gt;DataStoreSettings&lt;/code&gt;), but the alternative is wrapping a lot of &lt;code&gt;runBlocking&lt;/code&gt; which feels worse. I like the current state of things where you can use the non-coroutine interfaces with internal &lt;code&gt;runBlocking&lt;/code&gt; if you want by calling &lt;code&gt;toBlockingSettings()&lt;/code&gt; or &lt;code&gt;toBlockingObservableSettings()&lt;/code&gt;, because it makes the blocking explicit and opt-in. But I'd like to hear if it works for you too. You can leave feedback in &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/119" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Serialization integration
&lt;/h3&gt;

&lt;p&gt;For the &lt;code&gt;multiplatform-settings-serialization&lt;/code&gt; APIs, I want to know if people find this integration useful. I've already had some good feedback around adding &lt;code&gt;remove()&lt;/code&gt; and &lt;code&gt;contains()&lt;/code&gt; analogs for serializable values, and there's a PR open that serves as a proof-of-concept. I'd love to hear feedback on &lt;a href="https://github.com/russhwolf/multiplatform-settings/pull/117" rel="noopener noreferrer"&gt;that PR&lt;/a&gt; or the &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/81" rel="noopener noreferrer"&gt;linked issue&lt;/a&gt;. I'd also like to hear what else is missing from these APIs. You can leave feedback in &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/120" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Apple Keychain integration
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;KeychainSettings&lt;/code&gt; implementation is experimental because it hasn't been heavily battle-tested yet. If you've tried it, please let me know if it meets your security needs. If you or someone you know is well-versed in the keychain APIs, I'd love a review of whether the implementation is doing everything it needs to in terms of security. You can leave any of this feedback in the &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/121" rel="noopener noreferrer"&gt;related issue&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows implementation
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;RegistrySettings&lt;/code&gt; implementation on Windows is experimental largely because I want to add &lt;code&gt;ObservableSettings&lt;/code&gt; support, and I want to reserve the possibility of breaking changes until that's in place. If you have ideas about this or want to help out, let me know in the &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/51" rel="noopener noreferrer"&gt;related issue&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Linux implementation
&lt;/h3&gt;

&lt;p&gt;At the moment, there is no desktop Linux &lt;code&gt;Settings&lt;/code&gt; implementation. I've created various prototypes over the years, but it's not a development environment I spend much time in so I have no insight into what's useful. You can see some of the things I've tried in the PRs linked from &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/113" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;. The feedback that's most important to me is what backing API would most useful from an interop perspective if you have some shared and some platform-specific code. It doesn't have to be one of the ones I've already tried.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next for 1.0?
&lt;/h2&gt;

&lt;p&gt;Ok that was a lot of text. Thanks for sticking with me as I braindump the state of the library and the roadmap to 1.0 and beyond.&lt;/p&gt;

&lt;p&gt;I think I'd like to aim the final 1.0 release for around the Kotlin 1.8 timeframe, which will be sometime this fall. So I'd love to hear what folks think of these changes, and of the library overall. If there's anything else you think should change while the library is still in the pre-1.0 stage, now is the time to let me know!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
    </item>
    <item>
      <title>Trying out the experimental new Kotlin/Native memory model</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Sat, 07 Aug 2021 15:54:36 +0000</pubDate>
      <link>https://dev.to/touchlab/trying-out-the-experimental-new-kotlin-native-memory-model-235k</link>
      <guid>https://dev.to/touchlab/trying-out-the-experimental-new-kotlin-native-memory-model-235k</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@victorserban?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Victor Serban&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update Aug 12, 2021: This article has been updated with a new section about using the new memory model with &lt;code&gt;kotlinx-coroutines&lt;/code&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've been following Kotlin/Native at all over the last couple of years, you'll know that it's memory model has been controversial. Last year, the Kotlin team &lt;a href="https://blog.jetbrains.com/kotlin/2020/07/kotlin-native-memory-management-roadmap/" rel="noopener noreferrer"&gt;committed to redesigning it&lt;/a&gt;, and this year they &lt;a href="https://blog.jetbrains.com/kotlin/2021/05/kotlin-native-memory-management-update/" rel="noopener noreferrer"&gt;promised a preview&lt;/a&gt; by the end of the summer. Well, there hasn't been an official announcement yet, but that preview is present in the Kotlin 1.5.30 early-access release.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL,DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Update your Kotlin version to 1.5.30-RC&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;kotlinOptions.freeCompilerArgs += listOf("-memory-model", "experimental")&lt;/code&gt; to your Kotlin/Native compilations&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;kotlin.native.cacheKind=none&lt;/code&gt; to &lt;code&gt;gradle.properties&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To use coroutines with the new model, add &lt;code&gt;https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven&lt;/code&gt; to repositories and use version &lt;code&gt;1.5.1-new-mm-dev1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mutate unfrozen objects from different threads&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wait, what?!
&lt;/h2&gt;

&lt;p&gt;Yup! The memory model is controlled with the &lt;code&gt;-memory-model&lt;/code&gt; command-line flag. Pass &lt;code&gt;experimental&lt;/code&gt; for the new model or &lt;code&gt;strict&lt;/code&gt; for the existing one&lt;sup&gt;*&lt;/sup&gt;. Due to current limitations, you also need to disable compiler caching with the &lt;code&gt;kotlin.native.cacheKind=none&lt;/code&gt; gradle property.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;sup&gt;*&lt;/sup&gt;You can also pass &lt;code&gt;relaxed&lt;/code&gt;, but it's probably not a good idea.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can pass the flag to all your Kotlin/Native targets by doing something like this from Gradle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KotlinNativeTarget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;compilations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kotlinOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;freeCompilerArgs&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; 
                &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-memory-model"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"experimental"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can freely mutate unfrozen state across threads. Let's see what that looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the two models
&lt;/h2&gt;

&lt;p&gt;In the current strict memory model, if you wanted to write a function to run code in a background thread, it might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doInBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;worker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;future&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;TransferMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SAFE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function takes a lambda, freezes it, and executes it in a new &lt;code&gt;Worker&lt;/code&gt; which runs on a background thread. Because the lambda is frozen, the only way we can have mutable state is by using atomics, as in the following test (which can run on the &lt;code&gt;iosX64&lt;/code&gt; target)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;oldMemoryTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AtomicReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;doInBackground&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;didRunLambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;didRunLambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we initialize an atomic boolean to false on the main thread, mutate it to true on a background thread, and assert that it's true from the main thread.&lt;/p&gt;

&lt;p&gt;Code like the above is the primary way of handling mutable state across threads in the current memory model (although it's usually hidden deep in the machinery of a library like &lt;code&gt;kotlinx.coroutines&lt;/code&gt;), and it still works in the experimental model. But we can also do new things we coudln't do before. &lt;/p&gt;

&lt;p&gt;We might naively expect that the new model will just let us drop the atomic and do something like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;newMemoryTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;doInBackground&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// *&lt;/span&gt;
        &lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;didRunLambda&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this will fail at the starred line with an &lt;code&gt;InvalidMutabilityException&lt;/code&gt;. Our &lt;code&gt;doInBackground()&lt;/code&gt; function freezes the lambda, and the new memory model still respects freeze semantics and doesn't allow frozen things to change. That includes the &lt;code&gt;didRunLambda&lt;/code&gt; boolean which is captured from the outer scope.&lt;/p&gt;

&lt;p&gt;So let's create a new backgrounding function. Note that this function works only in the new model, and will fail with an &lt;code&gt;IllegalStateException&lt;/code&gt; if you use the existing strict memory model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doInBackgroundUnfrozen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;worker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;future&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;TransferMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SAFE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// No more freeze() call&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subbing this function into the test allows it to pass in the new model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;newMemoryTestUnfrozen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;doInBackgroundUnfrozen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;didRunLambda&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Coroutines
&lt;/h2&gt;

&lt;p&gt;There's also now a early dev release of coroutines with the new model! It's available from the coroutines internal maven repo, so you need to add it to your repositories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nf"&gt;maven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can add the coroutines dependency with version &lt;code&gt;1.5.1-new-mm-dev1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;commonMain&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;getting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// ...&lt;/span&gt;
                &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-new-mm-dev1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can scrap &lt;code&gt;doInBackground()&lt;/code&gt; and &lt;code&gt;doInBackgroundUnfrozen()&lt;/code&gt;, and just use &lt;code&gt;withContext()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;newMemoryCoroutinesTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;runBlocking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;withContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;didRunLambda&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;didRunLambda&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Further thoughts
&lt;/h2&gt;

&lt;p&gt;It's pretty neat seeing this in action! As the Kotlin team promised previously, existing code written around &lt;code&gt;freeze()&lt;/code&gt; in the strict memory model still appears to behave the same in the new experimental model. But we also now have the ability to pass unfrozen things across threads. This should mean that, once the model is finalized, existing code won't need to migrate immediately. However, early adopters of the experimental model will likely need to wait for any concurrency libraries they depend on to update, or else they'll still need to handle the existing &lt;code&gt;freeze()&lt;/code&gt; behavior. That work has &lt;a href="https://github.com/Kotlin/kotlinx.coroutines/issues/2797" rel="noopener noreferrer"&gt;already begun&lt;/a&gt; in kotlinx.coroutines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;The experimental new memory model is an undocumented preview release. I haven't tried much beyond what's presented here, and I have no idea what limitations or possible issues there are. Use at your own risk! That said, it might be a nice time to try it out, especially if you maintain library code that handles freeze-related logic currently. Be sure to report any bugs you see, and give JetBrains feedback on if it works for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I use this in production?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Let me know in the comments if you have questions, or you can reach out to me at &lt;a class="mentioned-user" href="https://dev.to/russhwolf"&gt;@russhwolf&lt;/a&gt; on &lt;a href="https://twitter.com/RussHWolf" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or the &lt;a href="https://slack.kotlinlang.org" rel="noopener noreferrer"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/" rel="noopener noreferrer"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
    </item>
    <item>
      <title>Kotlin Coroutines and Swift, revisited</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Fri, 04 Jun 2021 20:50:38 +0000</pubDate>
      <link>https://dev.to/touchlab/kotlin-coroutines-and-swift-revisited-j5h</link>
      <guid>https://dev.to/touchlab/kotlin-coroutines-and-swift-revisited-j5h</guid>
      <description>&lt;p&gt;Last year I wrote about a pattern for interop between &lt;a href="https://dev.to/touchlab/working-with-kotlin-coroutines-and-rxswift-24fa"&gt;Kotlin coroutines and RxSwift&lt;/a&gt;. I appreciate the attention it received, particularly where people have applied it to &lt;a href="https://johnoreilly.dev/posts/kotlinmultiplatform-swift-combine_publisher-flow/" rel="noopener noreferrer"&gt;other reactive frameworks&lt;/a&gt;, and even including a &lt;a href="https://github.com/FutureMind/koru" rel="noopener noreferrer"&gt;code-generation plugin&lt;/a&gt; using the same ideas. I figure it's about time I talk about my own updated thinking on these patterns.&lt;/p&gt;

&lt;p&gt;If you haven't read the previous article, I suggest going through that first for context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kotlin updates
&lt;/h2&gt;

&lt;p&gt;We'll stick to the same repository class as the original article, and walk through exposing it to iOS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"oh no!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"oops!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the previous article, I suggested the following pattern for wrapping suspend functions with callbacks that could run on iOS&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After having played with these patterns more, a drawback to this emerged. This class expects a &lt;code&gt;CoroutineScope&lt;/code&gt; to be supplied by the caller (which will be in Swift) at subscription time. This can be nice for flexibility if it might be called in different contexts, but in the vast majority of cases in practice this will live in some sort of class with its own scope, and it's much more pleasant to work with the scope from Kotlin than from Swift. So let's make the scope a constructor parameter instead.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A similar change can be made for &lt;code&gt;FlowWrapper&lt;/code&gt;. Now we can manage that scope in the iOS repository class, at the Kotlin level.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingRepositoryIos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ThingRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SupervisorJob&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingStreamWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;FlowWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we can drop the scope parameter from the RxSwift subscribe calls.&lt;/p&gt;
&lt;h2&gt;
  
  
  Swift repository wrappers
&lt;/h2&gt;

&lt;p&gt;The previous article didn't consider Swift-side architecture beyond the &lt;code&gt;createObservable()&lt;/code&gt; and &lt;code&gt;createSingle()&lt;/code&gt; functions. But in practice you aren't likely to want to call these inline at every call-site. You can add one more wrapper layer in Swift so that the rest of the Swift side of the codebase doesn't need to know about the Kotlin classes at all. For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ThingRepositoryRxSwift&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ThingRepositoryIos&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ThingRepositoryIos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ThingRepository&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Single&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Thing&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createSingle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;suspendWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getThingStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Thing&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flowWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingStreamWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the rest of the code sees only &lt;code&gt;ThingRepositoryRxSwift&lt;/code&gt; and its RxSwift API and the Kotlin essentially becomes an implementation detail.&lt;/p&gt;
&lt;h2&gt;
  
  
  Combine
&lt;/h2&gt;

&lt;p&gt;The other thing I've done more thinking about since the original article is how this can apply to the Combine framework. Combine has a &lt;code&gt;Publisher&lt;/code&gt; type which represents an observable stream with a particular type of event and error.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;flowWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlowWrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Deferred&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HandleEvents&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flowWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;receiveCancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This makes use of a &lt;code&gt;PassthroughSubject&lt;/code&gt; to handle the heavy lifting, and simply forwards the &lt;code&gt;Flow&lt;/code&gt; events from our &lt;code&gt;FlowWrapper&lt;/code&gt; callbacks to it. It makes use of the same &lt;code&gt;KotlinError&lt;/code&gt; error type as the previous article. Note the &lt;code&gt;eraseToAnyPublisher()&lt;/code&gt; call at the end, which cleans up our return type to &lt;code&gt;AnyPublisher&amp;lt;T, KotlinError&amp;gt;&lt;/code&gt; instead of &lt;code&gt;Deferred&amp;lt;Publishers.HandleEvents&amp;lt;PassthroughSubject&amp;lt;T, KotlinError&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;. Combine's generic internals are weird but they give us this utility to hide them.&lt;/p&gt;

&lt;p&gt;For single-event streams, Combine has a &lt;code&gt;Future&lt;/code&gt; type. Unfortunately, there's no &lt;code&gt;eraseToAnyFuture()&lt;/code&gt; helper that I could find, so we still end up typed as a multi-event &lt;code&gt;Publisher&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;suspendWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;AnyPublisher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Deferred&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Publishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HandleEvents&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Kotlinx_coroutines_coreJob&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Future&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;promise&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;suspendWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nv"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="nv"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;receiveCancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eraseToAnyPublisher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You could also do something similar with a &lt;code&gt;PassthroughSubject&lt;/code&gt;, but I suspect (without having profiled extensively) that this version is probably lighter. There's also &lt;a href="https://github.com/apple/swift-evolution/blob/main/proposals/0296-async-await.md" rel="noopener noreferrer"&gt;async/await support&lt;/a&gt; on the horizon for Swift, which would be nice to integrate here in the future.&lt;/p&gt;
&lt;h3&gt;
  
  
  SwiftUI
&lt;/h3&gt;

&lt;p&gt;One of the nice things about using Combine is it integrates well with SwiftUI. You can create a model class like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ThingModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@Published&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ThingRepositoryIos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createPublisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;flowWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingStreamWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and then observe the &lt;code&gt;Thing&lt;/code&gt; in a view like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ThingView&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@ObservedObject&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;thingModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ThingModel&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ThingRepositoryIos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;thingModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ThingModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Count: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;thingModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Isn't this a lot of boilerplate?
&lt;/h2&gt;

&lt;p&gt;There's obviously a lot of layers here, and that can be a bit off-putting. However, I think this sort of layering is a helpful pattern in a lot of Swift/Kotlin interop.&lt;/p&gt;

&lt;p&gt;We have two different languages that we're trying to make talk to each other. While for most simple use-cases the interop is &lt;a href="https://kotlinlang.org/docs/native-objc-interop.html" rel="noopener noreferrer"&gt;handled for us by the compiler&lt;/a&gt;, in more complex situations we need to carve out a shared cross-language interface by hand. This will often take the form of a Kotlin wrapper layer that's less idiomatic to Kotlin consumers but is possible for Swift to consume, and then an extra Swift layer to take those Kotlin wrappers and massage them into more idiomatic Swift code.&lt;/p&gt;

&lt;p&gt;We shouldn't be surprised that this extra glue code is needed, given the differences in language and environment. Most of it is either things we only need to write once (like the &lt;code&gt;SuspendWrapper&lt;/code&gt; class in Kotlin or the &lt;code&gt;createObservable()&lt;/code&gt; or &lt;code&gt;createPublisher()&lt;/code&gt; functions in Swift), or things that follow very consistent patterns that we might be able to codegen (like creating &lt;code&gt;ThingRepositoryIos&lt;/code&gt; based on &lt;code&gt;ThingRepository&lt;/code&gt; in Kotlin, or &lt;code&gt;ThingModel&lt;/code&gt; in Swift). &lt;/p&gt;

&lt;p&gt;Sure, this extra infrastructure wouldn't be needed if we were writing a pure native iOS app in Swift. But we've gained the ability to share Kotlin code into Swift in a more idiomatic way. I tend to think the tradeoff is worth it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;I'd like to further iterate on all these patterns in some form of codegen library in the future, as compiler plugins start to mature. I'm hopeful for a multiplatform version of &lt;a href="https://github.com/google/ksp/" rel="noopener noreferrer"&gt;Kotlin Symbol Processing&lt;/a&gt; to help with this, though this won't be possible before Kotlin 1.5.20 at the earliest due to missing extension points in the Kotlin compiler. Fingers crossed for something this summer I guess.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2023 Update&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;As of 2023, Touchlab has introduced a new tool to help with flow and suspend interop, as well as sealed classes wrapped as enums. We are pleased to introduce you to SKIE, Swift/Kotlin Interface Extender. For more information and to sign up for a demo, please visit &lt;a href="//skie.touchlab.co"&gt;skie.touchlab.co&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you'd like to play with all of this yourself, updated code samples are available at the following repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/touchlab" rel="noopener noreferrer"&gt;
        touchlab
      &lt;/a&gt; / &lt;a href="https://github.com/touchlab/SwiftCoroutines" rel="noopener noreferrer"&gt;
        SwiftCoroutines
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;As before, this includes nullable and non-null versions of both single-event and multiple-event streams, and Swift unit tests to verify it all works correctly. In addition, there's now a SwiftUI display to demo the Combine code, as well as log-based demos of RxSwift and Combine bindings.&lt;/p&gt;




&lt;p&gt;Hope you enjoyed this! I'd love to hear feedback, either in the comments or on &lt;a href="https://kotlinlang.slack.com/archives/D2VU3UHU0" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; or &lt;a href="https://twitter.com/RussHWolf" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. If you'd like to go deeper, feel free to &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;reach out to Touchlab&lt;/a&gt;. We're also &lt;a href="https://touchlab.co/careers-3/" rel="noopener noreferrer"&gt;hiring&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>swift</category>
    </item>
    <item>
      <title>Multiplatform Settings version 0.7 is out!</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Sun, 27 Dec 2020 00:37:48 +0000</pubDate>
      <link>https://dev.to/russhwolf/multiplatform-settings-version-0-7-is-out-2l0</link>
      <guid>https://dev.to/russhwolf/multiplatform-settings-version-0-7-is-out-2l0</guid>
      <description>&lt;p&gt;Today I’ve released version 0.7 of &lt;a href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;Multiplatform Settings&lt;/a&gt;! There's a lot of new features in this one, including integrations with some of the kotlinx libraries which have been incubating in PRs for a long time, so I'm excited to hear what people think.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/russhwolf/multiplatform-settings/releases/tag/v0.7" rel="noopener noreferrer"&gt;Release Notes&lt;/a&gt;&lt;br&gt;
&lt;a href="https://search.maven.org/artifact/com.russhwolf/multiplatform-settings/0.7/pom" rel="noopener noreferrer"&gt;Maven Central&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Read on for more details on what's new.&lt;/p&gt;
&lt;h2&gt;
  
  
  Serialization
&lt;/h2&gt;

&lt;p&gt;I've had the idea in my head for a while that I'd like to generalize the existing delegate APIs to enable storing non-primitive data. Thanks to some suggestions from &lt;a href="https://twitter.com/workingkills" rel="noopener noreferrer"&gt;Eugenio Marletti&lt;/a&gt; and &lt;a href="https://github.com/sandwwraith" rel="noopener noreferrer"&gt;Leonid Startsev&lt;/a&gt; I came to realize how that could be done using kotlinx.serialization, by using its custom format APIs. There's been a PR open for a while which I iterated on as the serialization library adjusted those APIs and approached it's first stable release. Now that the library has reached 1.0, even if most of the encoder/decoder APIs are still experimental, it feels like the right time to release the integration with Multiplatform Settings.&lt;/p&gt;

&lt;p&gt;With this, if you have a serializable class like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can save an instance to &lt;code&gt;Settings&lt;/code&gt; by calling&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and retrieve it with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
    &lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;defaultValue&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;nullableUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeValueOrNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
    &lt;span class="s"&gt;"user"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or you could do both via a delegate api&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;user&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, it's no substitute for a structured database like sqlite if you need atomicity for more complex data, but for simple use-cases I hope people find it helpful. I also think it's also a neat demonstration of some less well-known parts of kotlinx.serialization, so I hope it can inspire other interesting custom formats as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coroutines
&lt;/h2&gt;

&lt;p&gt;Similar to serialization, there's been a PR up for a while with &lt;code&gt;Flow&lt;/code&gt; extensions on &lt;code&gt;ObservableSettings&lt;/code&gt;. That's finally merged in 0.7, with two different artifacts depending on whether you use the &lt;code&gt;native-mt&lt;/code&gt; branch of coroutines. I'm not sure having separate artifacts is totally necessary, but I figured it might help avoid people being forced to change which coroutines version they use just to interact with Settings. &lt;/p&gt;

&lt;h3&gt;
  
  
  Datastore
&lt;/h3&gt;

&lt;p&gt;Until recently I thought &lt;code&gt;Flow&lt;/code&gt; APIs would be the only interesting coroutine functionality worth adding to the library, but then the Android team released Jetpack DataStore. This includes a fully suspend-based key-value store intended to replace SharedPreferences. The existing &lt;code&gt;Settings&lt;/code&gt; API isn't a great fit for &lt;code&gt;DataStore&lt;/code&gt; since everything would need to be wrapped in &lt;code&gt;runBlocking&lt;/code&gt; calls internally, which could easily catch consumers by surprise.&lt;/p&gt;

&lt;p&gt;To better handle this with fewer surprises, I've added &lt;code&gt;SuspendSettings&lt;/code&gt; and &lt;code&gt;FlowSettings&lt;/code&gt; interfaces, which are essentially coroutine-based analogs of &lt;code&gt;Settings&lt;/code&gt; and &lt;code&gt;ObservableSettings&lt;/code&gt; (including that &lt;code&gt;FlowSettings&lt;/code&gt; extends &lt;code&gt;SuspendSettings&lt;/code&gt;). There's a &lt;code&gt;DataStoreSettings&lt;/code&gt; which is the only direct implementation of &lt;code&gt;FlowSettings&lt;/code&gt;, but there are also converters &lt;code&gt;Settings.toSuspendSettings()&lt;/code&gt; and &lt;code&gt;ObservableSettings.toFlowSettings()&lt;/code&gt; which wrap the non-coroutine interfaces in the suspending ones. This lets you use a single suspendable API from common if you're using DataStore on Android.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Common&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlowSettings&lt;/span&gt;

&lt;span class="c1"&gt;// Android&lt;/span&gt;
&lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlowSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataStoreSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...*/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// iOS&lt;/span&gt;
&lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlowSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AppleSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...*/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFlowSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feels like a lot of machinery just to interop with one API, but it seems important if DataStore is going to become the new key-value API of choice on Android. I've been watching its development closely and I'm interested to see if other async key-value libraries follow. If they do, Multiplatform Settings will be ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keychain
&lt;/h2&gt;

&lt;p&gt;I've been asked numerous times about secure storage. Android provides &lt;a href="https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences" rel="noopener noreferrer"&gt;EncryptedSharedPreferences&lt;/a&gt; as part of &lt;code&gt;androidx.security&lt;/code&gt;, which can be passed as a delegate to &lt;code&gt;AndroidSettings&lt;/code&gt; just like any other &lt;code&gt;SharedPreferences&lt;/code&gt; implementation, but there's no simple equivalent way to get encrypted storage on iOS or any other existing Settings platform. In 0.7 there's a new &lt;code&gt;KeychainSettings&lt;/code&gt; implementation available on Apple platforms, which stores data in the Keychain instead of in User Defaults. &lt;/p&gt;

&lt;p&gt;I'm not an expert in security or in the keychain APIs, so I'd appreciate feedback as to whether this fits your use-cases and security needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other little things
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Typed listeners
&lt;/h3&gt;

&lt;p&gt;In a quality-of-life improvement that I meant to throw in a long time ago and forgot about, there are now extension functions to allow typed listeners for &lt;code&gt;ObservableSettings&lt;/code&gt;. Where before you had to write code like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myInt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now you can shorten it to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIntListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myInt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sample updates
&lt;/h3&gt;

&lt;p&gt;Previously, the sample project got a little too cute with method references and other syntax shortcuts and it made it hard to see what typical usage of the library looks like. I've refactored it to focus more on the core APIs so it's easier to poke around and understand what's going on. I'd like to do more here in the future, since there's a lot of the library currently not touched by the sample app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desktop Linux
&lt;/h3&gt;

&lt;p&gt;I've had a &lt;a href="https://github.com/russhwolf/multiplatform-settings/pull/54" rel="noopener noreferrer"&gt;PR open&lt;/a&gt; for a while now with a desktop Linux Settings implementation based on QDBM. There's no good reason to use QDBM except that I originally prototyped it in the kotlin macos target which includes NDBM with very similar DBM-based APIs. I could merge it but I really have no idea if anyone would want to use it, or if wrapping some other API would be better. I'd very much like to hear from the desktop Linux dev community about what would be useful here since this is the only desktop platform currently missing a first-party implementation.&lt;/p&gt;




&lt;p&gt;Hopefully that was a helpful tour of the major new developments in Multiplatform Settings 0.7. I don't get a huge amount of feedback, so please do reach out and let me know what is and isn't working for you in the library, and if there's other features you're looking for. You can leave a comment on this blog, reach out to me on &lt;a href="https://twitter.com/russhwolf/" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://kotlinlang.slack.com/archives/D2VU3UHU0" rel="noopener noreferrer"&gt;Kotlin Slack&lt;/a&gt;, file a &lt;a href="https://github.com/russhwolf/multiplatform-settings/issues/new" rel="noopener noreferrer"&gt;Github issue&lt;/a&gt;, or start a thread on the brand new &lt;a href="https://github.com/russhwolf/multiplatform-settings/discussions" rel="noopener noreferrer"&gt;Multiplatform Settings Github Discussions board&lt;/a&gt;. And of course, be on the lookout for more updates to come!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>news</category>
    </item>
    <item>
      <title>Working with Kotlin Coroutines and RxSwift</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Mon, 15 Jun 2020 19:07:18 +0000</pubDate>
      <link>https://dev.to/touchlab/working-with-kotlin-coroutines-and-rxswift-24fa</link>
      <guid>https://dev.to/touchlab/working-with-kotlin-coroutines-and-rxswift-24fa</guid>
      <description>&lt;p&gt;A recent client engagement involved interop between Kotlin coroutines in shared code, and RxSwift on the iOS side. We did some work to ensure that this could be done in a way that is type-safe and thread-safe. Whether or not you use RxSwift, hopefully this can provide some useful patterns for interop code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/coroutines-overview.html" rel="noopener noreferrer"&gt;Coroutines&lt;/a&gt; are a Kotlin language feature that allows asynchronous code to be written in a way that looks like synchronous code, avoiding the nesting that often comes with callback-based APIs. They're available on all Kotlin platforms, but have some limitations on the native side. The release version of native coroutines is limited to single-threaded use-cases, though there are experimental releases available that are multithreaded with some risk of memory leaks. But while they're a fully-supported language feature of Kotlin, they don't translate to Objective-C and Swift.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ReactiveX/RxSwift" rel="noopener noreferrer"&gt;RxSwift&lt;/a&gt; is a Swift implementation of the &lt;a href="http://reactivex.io/" rel="noopener noreferrer"&gt;Reactive Streams&lt;/a&gt; specification. It's one way to handle asynchronous code on Swift, and has many operators for combining and transforming event streams. Though some of the names are different, much of the API will feel familiar to Kotlin developers who have experience with RxJava.&lt;/p&gt;

&lt;p&gt;Since Coroutines will almost always be present in shared code, and RxSwift is a common option on the iOS side, hopefully the motivation to communicate between them is clear. So let’s start writing some code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Repository
&lt;/h3&gt;

&lt;p&gt;We’ll work with a dummy repository class that looks like this, defined in &lt;code&gt;src/commonMain&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"oh no!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"oops!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;From the outside this looks roughly like a real repository might, but with inputs that let us control the output a bit more directly for demonstration purposes. It gives us the ability to test success and error cases for both single-event &lt;code&gt;suspend&lt;/code&gt; functions, and multiple-event &lt;code&gt;Flow&lt;/code&gt;s. The internal delays also give us a chance to cancel things in-flight so we can verify that works as expected.&lt;/p&gt;

&lt;p&gt;Of course, if we try to consume this repository from Swift code, we run into some immediate problems. Suspend functions are not visible at all to Swift&lt;sup&gt;*&lt;/sup&gt;, and while the &lt;code&gt;Flow&lt;/code&gt; type is visible, most APIs you might call on it are not. Further, &lt;code&gt;Flow&lt;/code&gt;'s generic type is not visible to Swift, due to limitations in how generics are translated from Kotlin, though Objective-C, and then to Swift. Generic arguments only make it from Kotlin to Swift when defined on classes, and &lt;code&gt;Flow&lt;/code&gt; is an interface.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;*&lt;/sup&gt;&lt;em&gt;This will be changing somewhat in Kotlin 1.4, where suspend functions will &lt;a href="https://blog.jetbrains.com/kotlin/2020/06/kotlin-1-4-m2-released/#native-suspending-functions-support" rel="noopener noreferrer"&gt;generate a callback function&lt;/a&gt; visible to Objective-C/Swift. However, this uses &lt;a href="https://dev.to/touchlab/kotlin-1-4-suspend-functions-209"&gt;only the language-level &lt;code&gt;suspend&lt;/code&gt; function support&lt;/a&gt;, and none of the extra functionality from the &lt;code&gt;kotlinx.coroutines&lt;/code&gt; library, so it doesn't help with cancellation or the structured concurrency model. We want to be able to control cancellation and threading via &lt;code&gt;CoroutineScope&lt;/code&gt;s, so the new stuff in 1.4 won't help here.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Suspend and Flow wrappers
&lt;/h3&gt;

&lt;p&gt;So, let's add some wrapper types that are easier to interact with from Swift. These are iOS-specific, so we can put them in the &lt;code&gt;iosMain&lt;/code&gt; source-set. First, &lt;code&gt;SuspendWrapper&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A couple things to highlight here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;subscribe&lt;/code&gt; function is a stand-in for invoking the lambda since that's impossible from Swift, but it also adds some callbacks. This lets us easily hook into the different Rx event callbacks. If we care about other parts of the Rx lifecycle like subscription and disposal we could add other lambdas here and call them at the appropriate time.&lt;/li&gt;
&lt;li&gt;There's a &lt;code&gt;scope&lt;/code&gt; parameter, which I left in to keep this architecture-agnostic. You could alternatively make the scope internal to the wrapper, if you want to assert that you always call this suspend function in a specific scope. This would be less flexible but would avoid some work on the Swift side.&lt;/li&gt;
&lt;li&gt;The generic parameter has an &lt;code&gt;Any&lt;/code&gt; upper-bound. Without this, all Swift references to &lt;code&gt;T&lt;/code&gt; would be nullable, even if a nonnull type were used for &lt;code&gt;T&lt;/code&gt;. If you need to work with nullable types, I recommend having a separate &lt;code&gt;NullableSuspendWrapper&lt;/code&gt; which differs only in the generic upper-bound.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there's still an issue. There's a good chance we'll want to talk to these wrappers in a multithreaded setting. In the default, single-threaded coroutines version, this would require the success and throw callbacks to switch back to the original thread before running, which is a heavy limitation. Things are easier if we use the multithreaded coroutines branch, but we still need to do some work to make this thread-safe for Kotlin/Native.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;suspender&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We've added &lt;code&gt;freeze()&lt;/code&gt; calls in three key places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On initialization, so the &lt;code&gt;SuspendWrapper&lt;/code&gt; itself can cross threads&lt;/li&gt;
&lt;li&gt;On the arguments of each callback, so that emissions or errors can be passed to other threads. &lt;/li&gt;
&lt;li&gt;On the &lt;code&gt;Job&lt;/code&gt; returned by the &lt;code&gt;subscribe()&lt;/code&gt; call, so that it can be cancelled from any thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Flow&lt;/code&gt; equivalent is this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlowWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flow&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;onEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCompletion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is similar to the structure of &lt;code&gt;SuspendWrapper&lt;/code&gt;, except that it wraps a &lt;code&gt;Flow&lt;/code&gt; instead of a &lt;code&gt;suspend&lt;/code&gt; function. An important but subtle detail is that the &lt;code&gt;catch{}&lt;/code&gt; call must come before &lt;code&gt;onCompletion{}&lt;/code&gt;, or else the &lt;code&gt;RxSwift&lt;/code&gt; stream will end before the error is emitted.&lt;/p&gt;
&lt;h3&gt;
  
  
  iOS Repository Wrapper
&lt;/h3&gt;

&lt;p&gt;With these function-level wrappers in place, we'll add an iOS wrapper around our &lt;code&gt;ThingRepository&lt;/code&gt; that makes use of them:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingRepositoryIos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ThingRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;CoroutineScope&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;coroutineContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CoroutineContext&lt;/span&gt;
            &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SupervisorJob&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
        &lt;span class="nc"&gt;SuspendWrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getThingStreamWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;FlowWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This piece is the unfortunate boilerplate we need in this scheme. While most of the other bridge code just has to be written once, each repository method must be explicitly wrapped into something visible from Swift, and we wrap the entire repository so we have a place to put them. At scale it would probably be preferable to codegen some version of this, but for something small it's pretty straightforward to write by hand.&lt;/p&gt;

&lt;p&gt;Note that we freeze this class to ensure it can safely be touched from a background thread, since it likely will be.&lt;/p&gt;

&lt;p&gt;We also declare a scope here. This will be passed as a parameter to the &lt;code&gt;subscribe()&lt;/code&gt; calls on &lt;code&gt;SuspendWrapper&lt;/code&gt; and &lt;code&gt;FlowWrapper&lt;/code&gt;. In this example it's using &lt;code&gt;Dispatchers.Default&lt;/code&gt;, which requires using the multithreaded coroutines branch.&lt;/p&gt;
&lt;h3&gt;
  
  
  Connecting Wrappers to Rx
&lt;/h3&gt;

&lt;p&gt;Armed with our iOS-compatible repository, it's time to move over into Swift. My natural inclination as a Kotlin developer is to add extension functions to &lt;code&gt;SuspendWrapper&lt;/code&gt; and &lt;code&gt;FlowWrapper&lt;/code&gt; which connect the relevant Rx piping to the callback lambdas inside the &lt;code&gt;subscribe()&lt;/code&gt; function. Unfortunately, the following declaration isn't valid here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;SuspendWrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;toSingle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Single&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This leads to an error stating &lt;code&gt;Extension of a generic Objective-C class cannot access the class's generic parameters at runtime&lt;/code&gt;. I don't have a deep understanding here, but essentially due to the different generic models between Swift and Objective-C, the generic parameter on &lt;code&gt;SuspendWrapper&lt;/code&gt; is erased at runtime and so the extension can't be resolved. Luckily, we can still define top-level functions:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createSingle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Kotlinx_coroutines_coreCoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;suspendWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SuspendWrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Single&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Single&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Kotlinx_coroutines_coreJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;suspendWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nv"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Disposables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createObservable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Kotlinx_coroutines_coreCoroutineScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;flowWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlowWrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Kotlinx_coroutines_coreJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flowWrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;onEach&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nv"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nv"&gt;onThrow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Disposables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These functions take in a &lt;code&gt;CoroutineScope&lt;/code&gt; and a &lt;code&gt;SuspendWrapper&lt;/code&gt; or &lt;code&gt;FlowWrapper&lt;/code&gt;, and create the associated Rx type &lt;code&gt;Single&lt;/code&gt; or &lt;code&gt;Observable&lt;/code&gt;. Rx events get forwarded to the callback lambdas that the wrappers defined, and the Rx disposable is linked to the coroutine &lt;code&gt;Job&lt;/code&gt; so that cancellation on the Rx side shuts down the coroutine as well.&lt;/p&gt;
&lt;h4&gt;
  
  
  By the way, a note on errors
&lt;/h4&gt;

&lt;p&gt;You might note the &lt;code&gt;KotlinError&lt;/code&gt; class referenced here. This is a simple wrapper to pass Kotlin exceptions into the Rx error stream, and forward the error message.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;KotlinError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;LocalizedError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;KotlinThrowable&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;KotlinThrowable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throwable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;errorDescription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This lets us read out the Kotlin error message from Swift by reading the &lt;code&gt;localizedDescription&lt;/code&gt; field on the error, without needing to check its type. This helps avoid extra Kotlin-specific error-handling in Swift.&lt;/p&gt;
&lt;h3&gt;
  
  
  Usage From Elsewhere in iOS App
&lt;/h3&gt;

&lt;p&gt;The rest of the Swift code can now talk to these observables, like so:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;disposable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;flowWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getThingStreamWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"next: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nv"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nv"&gt;onCompleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"complete"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nv"&gt;onDisposed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"disposed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will print&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;next: Thing(count=0)
next: Thing(count=1)
next: Thing(count=2)
complete!
disposed!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So there you have it: type-safe and thread-safe communication from Swift with coroutine APIs defined in our shared Kotlin, via RxSwift.&lt;/p&gt;
&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;I didn't emphasize it very heavily above, but only the Swift side of this setup has any knowledge of RxSwift. So if you want to do something similar with some other reactive API (I hear Combine is interesting), you could probably do so without needing to change anything on the Kotlin side.&lt;/p&gt;

&lt;p&gt;If you'd like to explore further, you can find the code at the following repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/touchlab" rel="noopener noreferrer"&gt;
        touchlab
      &lt;/a&gt; / &lt;a href="https://github.com/touchlab/SwiftCoroutines" rel="noopener noreferrer"&gt;
        SwiftCoroutines
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The repository has since been updated for the &lt;a href="https://dev.to/touchlab/kotlin-coroutines-and-swift-revisited-j5h"&gt;sequel to this blog post&lt;/a&gt;, but you can find the state of the code when this post was originally written in the &lt;code&gt;v1&lt;/code&gt; branch&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This includes a few extensions on what was presented here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Both nullable and nonnull versions of all &lt;a href="https://github.com/touchlab/SwiftCoroutines/blob/master/shared/src/iosMain/kotlin/co/touchlab/swiftcoroutines/SwiftCoroutines.kt" rel="noopener noreferrer"&gt;Kotlin wrapper types&lt;/a&gt; and &lt;a href="https://github.com/touchlab/SwiftCoroutines/blob/master/ios/SwiftCoroutines/RxSwiftWrappers.swift" rel="noopener noreferrer"&gt;Swift wrapper functions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/touchlab/SwiftCoroutines/blob/master/ios/SwiftCoroutinesTests/SwiftCoroutinesTests.swift" rel="noopener noreferrer"&gt;Swift unit tests&lt;/a&gt; to verify everything is working&lt;/li&gt;
&lt;li&gt;An extra &lt;code&gt;jobCallback&lt;/code&gt; parameter in &lt;code&gt;wrapSingle()&lt;/code&gt; and its siblings so that the Swift tests can pull the internally-created &lt;code&gt;Job&lt;/code&gt; out and verify it gets cancelled when expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hopefully this tour of RxSwift and Coroutines interop was interesting and helpful to you. And if you'd like to go deeper, you can always &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;reach out to Touchlab&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>ios</category>
    </item>
    <item>
      <title>Multiplatform Settings version 0.6 is out!</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Sun, 26 Apr 2020 20:03:33 +0000</pubDate>
      <link>https://dev.to/russhwolf/multiplatform-settings-version-0-6-is-out-2i41</link>
      <guid>https://dev.to/russhwolf/multiplatform-settings-version-0-6-is-out-2i41</guid>
      <description>&lt;p&gt;Today I’ve released version 0.6 of &lt;a href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;Multiplatform Settings&lt;/a&gt;! I thought I’d write a few words about what’s been added and what’s still to come.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;One major new feature is a Windows implementation which stores data in the registry. For that I’m thankful for the initial contribution from Andrew Mikhaylov, without which I wouldn’t have known how any of the Windows APIs work. It currently doesn’t implement the listener APIs in &lt;code&gt;ObservableSettings&lt;/code&gt;, but it should be possible to get something working in the future, using something like &lt;a href="https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regnotifychangekeyvalue" rel="noopener noreferrer"&gt;RegNotifyChangeKeyValue&lt;/a&gt;. Contributions welcome. If you do native Windows work, let me know if it meets your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  no-arg
&lt;/h3&gt;

&lt;p&gt;Another new feature is a new module called &lt;code&gt;multiplatform-settings-no-arg&lt;/code&gt;. This is in response to a longstanding friction I’ve heard of from some users, where configuration can seem too complicated. I’ve generally focused the design of Multiplatform Settings around platform interop, with the expectation that you probably have some existing key-value storage that you want to use from both your shared and platform-specific code. But if that doesn’t matter for your use-case, needing to configure things separately from each platform can be frustrating. So the no-arg module lets you call &lt;code&gt;Settings()&lt;/code&gt; from common code. Note that this is not currently implemented on Windows, but it is available for other existing platforms. More details in the &lt;a href="https://github.com/russhwolf/multiplatform-settings/blob/master/README.md#no-arg-module" rel="noopener noreferrer"&gt;readme&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;keys&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; APIs
&lt;/h3&gt;

&lt;p&gt;A minor update is the addition of &lt;code&gt;size&lt;/code&gt; and &lt;code&gt;keys&lt;/code&gt; APIs, which have been a longstanding to-do item of mine. I held off for a while because they behave unintuitively on Apple platforms, where after a &lt;code&gt;clear()&lt;/code&gt; call some keys are still present. However, after realizing that this might already be confusing for the &lt;code&gt;hasKey()&lt;/code&gt; API that already exists, I decided that it wasn’t a reason to keep them out of the library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listener updates
&lt;/h3&gt;

&lt;p&gt;Finally, this release brings better thread-safety for update listeners on Apple platforms. This is something I’ve been wanting to get back and improve for a long time, and is the biggest reason the listeners are still marked experimental. To avoid forcing all listeners to freeze, there’s a flag you can pass to &lt;code&gt;AppleSettings&lt;/code&gt; on creation. If &lt;code&gt;useFrozenListeners&lt;/code&gt; is false, you get the pre-existing behavior, where nothing gets frozen but you’ll get freeze exceptions if you update from a background thread and trigger a callback. If &lt;code&gt;useFrozenListeners&lt;/code&gt; is true, it is safe to update things from arbitrary threads, but the listener lambda will be frozen, so you must be sure not to accidentally capture mutable state. Try it out and let me know how it works for you! Thanks to Kevin Galligan for feedback on an early draft of the code.&lt;/p&gt;




&lt;p&gt;A couple things I’ve had on the to-do list are still in-progress. I’ve done some prototyping of integrations with both kotlinx.coroutines and kotlinx.serialization. The coroutine branch I’ve chosen to hold off on for a little while longer to do some thinking about how to handle threading, but the pull-request is available if you’d like to manually add it to your own code. The serialization integration needs more work in order to avoid calling into internal APIs, and is missing some functionality like collections. I’ve also been doing some prototyping of a desktop Linux implementation using DBM-style APIs. I haven’t been able to get it working yet, but I’d also love to get some feedback on whether that’s actually a useful direction to go in for interop purposes, or if there’s something else better to use.&lt;/p&gt;




&lt;p&gt;Full changelog of 0.6 is available &lt;a href="https://github.com/russhwolf/multiplatform-settings/releases/tag/v0.6" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and you can download it now on &lt;a href="https://bintray.com/beta/#/russhwolf/multiplatform-settings/multiplatform-settings/0.6?tab=overview" rel="noopener noreferrer"&gt;jcenter()&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, as a bonus, I've also published version &lt;a href="https://bintray.com/beta/#/russhwolf/multiplatform-settings/multiplatform-settings/0.6-1.4-M1?tab=overview" rel="noopener noreferrer"&gt;0.6-1.4-M1&lt;/a&gt;. This is the same as 0.6, but built against the Kotlin 1.4-M1 preview release. Check it out if you like living in the future.&lt;/p&gt;

&lt;p&gt;Happy Kotlin!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>news</category>
    </item>
    <item>
      <title>Kotlin 1.3.70 Reactions</title>
      <dc:creator>Russell Wolf</dc:creator>
      <pubDate>Thu, 05 Mar 2020 18:11:44 +0000</pubDate>
      <link>https://dev.to/touchlab/kotlin-1-3-70-reactions-3de3</link>
      <guid>https://dev.to/touchlab/kotlin-1-3-70-reactions-3de3</guid>
      <description>&lt;p&gt;Kotlin 1.3.70 is here! As the &lt;a href="https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/" rel="noopener noreferrer"&gt;release blog post&lt;/a&gt; says, there’s not much in the way of major landmark new features, but lots of incremental improvements and some interesting little quality-of-life stuff which I’m excited about. It's the first new language version since KotlinConf so it's cool to see some of the things JetBrains has been working on since then, even if a lot of the big-ticket stuff won't come until 1.4.&lt;/p&gt;

&lt;p&gt;Before we jump in, a quick reminder for Multiplatform users: Since Kotlin/Native is still in Beta, binaries are not compatible across versions. This means that you shouldn't update your Multiplatform projects until all of your library dependencies have Kotlin 1.3.70-compatible versions. If you're a &lt;a href="https://github.com/touchlab/KaMPKit" rel="noopener noreferrer"&gt;KaMPKit&lt;/a&gt; user, you can follow &lt;a href="https://github.com/touchlab/KaMPKit/issues/62" rel="noopener noreferrer"&gt;this issue&lt;/a&gt; to see when the libraries we use in that template are ready.&lt;/p&gt;




&lt;p&gt;Here's a couple of items in the blog post I thought were noteworthy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Renaming of experimental annotations
&lt;/h4&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been using &lt;code&gt;@Experimental&lt;/code&gt; and &lt;code&gt;@UseExperimental&lt;/code&gt; for over a year now in &lt;a href="https://github.com/russhwolf/multiplatform-settings" rel="noopener noreferrer"&gt;Multiplatform Settings&lt;/a&gt;, and find it to be a really nice way for libraries to mark more volatile APIs. Simply create an &lt;code&gt;annotation class MyExperimentalApi&lt;/code&gt; and annotate it with &lt;code&gt;@Experimental&lt;/code&gt;, and then consumers of anything marked &lt;code&gt;@MyExperimentalApi&lt;/code&gt; will have to explicitly opt-in to their dependence on experimental behavior.&lt;/p&gt;

&lt;p&gt;But I've also noticed some usage in the wild (including in JetBrains' own libraries) where it was more about marking internal APIs they didn't want other people depending on, rather than just APIs that might be unstable. So I'm not surprised that they're renaming these to &lt;code&gt;@RequiresOptIn&lt;/code&gt; and &lt;code&gt;@OptIn&lt;/code&gt; to broaden the usage. &lt;/p&gt;

&lt;p&gt;A side note here since I've seen people miss this: A &lt;code&gt;@RequiresOptIn&lt;/code&gt; annotation deliberately leaks to callers so that they're forced to opt-in as well. If you don't want to do that (for instance, because the experimental usage is just an internal implementation detail), you should use &lt;code&gt;@OptIn(MyExperimentalApi::class)&lt;/code&gt; instead so you only need to annotate at the direct use-site. You can also pass opt-ins at the command-line or gradle level that apply application-wide.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Double-ended queue implementation: ArrayDeque
&lt;/h4&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a neat one which I hadn't been tracking the development of. &lt;code&gt;ArrayDeque&lt;/code&gt; is a common default implementation for a &lt;code&gt;Queue&lt;/code&gt; or a &lt;code&gt;Stack&lt;/code&gt; on the JVM, but no such standard implementation existed on other platforms previously. That will be a welcome addition to people in need of these data structures in common code.&lt;/p&gt;

&lt;p&gt;The fact that it's a new implementation even on the JVM rather than delegating to the Java one is interesting, and atypical for Kotlin. I guess the benefit is that it allows them to improve the API some, by allowing it to be treated as a &lt;code&gt;List&lt;/code&gt; which isn't possible for the Java implementation. On the other hand it makes it less useful for Java interop. Interestingly, they have not actually added &lt;code&gt;Queue&lt;/code&gt; and &lt;code&gt;Stack&lt;/code&gt; interfaces to &lt;code&gt;kotlin.collections&lt;/code&gt;, so for example you'd get stack behavior by calling &lt;code&gt;addFirst()&lt;/code&gt; and &lt;code&gt;removeFirst()&lt;/code&gt; rather than &lt;code&gt;push()&lt;/code&gt; and &lt;code&gt;pop()&lt;/code&gt;. I'll be curious to see if these differences from Java have impact on how people use Kotlin's &lt;code&gt;ArrayDeque&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  IntelliJ IDEA support
&lt;/h4&gt;

&lt;p&gt;Now, the completion suggestions include functions declared in objects, including extension functions, object-level overrides, and even functions declared in nested objects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's nice to see support improving here for this &lt;a href="https://youtrack.jetbrains.com/issue/KT-15286" rel="noopener noreferrer"&gt;longstanding issue&lt;/a&gt;. The pattern of declaring extension functions in objects looks weird at first and doesn't feel all that idiomatic, but when combined with things like the &lt;code&gt;@JvmStatic&lt;/code&gt; annotation it's very helpful for maintaining clean interfaces for Java consumers. That means that libraries like &lt;a href="https://github.com/square/kotlinpoet" rel="noopener noreferrer"&gt;KotlinPoet&lt;/a&gt; and &lt;a href="https://square.github.io/okhttp/" rel="noopener noreferrer"&gt;OkHttp&lt;/a&gt; make heavy use of it, and so it's been a pain point that imports often need to be manually added from Kotlin. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Test results for Kotlin/JS and Kotlin/Native are now displayed right in the IntelliJ IDEA, as it has always been for Kotlin/JVM tests. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am already super pleased about this.&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1235041249020858370-825" src="https://platform.twitter.com/embed/Tweet.html?id=1235041249020858370"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1235041249020858370-825');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1235041249020858370&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Also, it's not called out in the blog, but a related improvement here is that the &lt;code&gt;iosX64Test&lt;/code&gt; gradle task (and the equivalent for other simulator targets) is built-in now, so we no longer have to define it manually. I've lost count of how many times I've copy/pasted that gradle snippet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;New inspection on pointless unary operators.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a subtle gotcha that's good to have some tooling help for. If you're not careful when splitting up a long math expression, you might end up with code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler will see this as two lines, so &lt;code&gt;a&lt;/code&gt; will have the value 5, and not 9 as you might expect. It's a subtle consequence of a language without semicolons, since the parser has to infer where one expression ends and the next begins. Glad we'll have an inspection calling it out, but I'd also love to see a quick-fix to convert it to the form you probably meant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
    &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the plus sign is at the end of the line, the compiler realizes that the 4 on the next line is part of the same expression and so &lt;code&gt;a&lt;/code&gt; would be 9 as expected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Kotlin/JS
&lt;/h4&gt;

&lt;p&gt;With Kotlin 1.3.70, we have made some long-awaited changes to the documentation and tutorials for the JavaScript target which hopefully makes it easier for people to get started with Kotlin/JS. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Been waiting on this one a while too. There were major updates to the JS gradle plugin API in 1.3.40 but updated documentation has been slow to arrive. Good to have it here now.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Kotlin/Native
&lt;/h4&gt;

&lt;p&gt;Support for multiple Kotlin frameworks in a single application&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;People have been asking for this for a while. There are some limitations to how multiple-framework applications will work, because each framework will have its own versions of the Kotlin standard library and any other common dependencies. However it should make the iOS developer experience more natural in some cases, especially in large multimodule projects. &lt;/p&gt;




&lt;p&gt;Lastly, I thought I’d mention one thing we didn’t see. Incremental experimental support has been increasing over the last few releases for “Hierarchical Multiplatform Projects” (HMPP). This is a &lt;a href="https://youtrack.jetbrains.com/issue/KT-27801" rel="noopener noreferrer"&gt;new internal model&lt;/a&gt; used by the gradle plugin and the IDE to infer things about intermediate shared sources, which differ from traditional common sources in that they can access platform-specific APIs which exist in all platforms the source-set compiles to. An example is accessing iOS APIs from code that is shared between iosArm64 (for iOS devices) and iosX64 (for the iOS simulator). I was hoping to see some details about this in the 1.3.70 announcement, but I guess it’s not quite ready yet. (Hopefully, the &lt;a href="https://youtrack.jetbrains.com/issue/KT-37155" rel="noopener noreferrer"&gt;bug I encountered&lt;/a&gt; right before the release didn’t throw too big a wrench in their plans). Looking forward to seeing what HMPP looks like in Kotlin 1.4 and beyond. &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image credit: JetBrains&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Justin Mancinelli, Sam Hill, Kevin Galligan, Erik Zambrano, Kevin Schildhorn, and Jeff Namnum for providing feedback on drafts of this post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>news</category>
    </item>
  </channel>
</rss>
