Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Promise and Peril of Kotlin Multiplatform

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

The Promise and Peril of Kotlin Multiplatform

Avatar for Justin Brooks

Justin Brooks

February 10, 2023

More Decks by Justin Brooks

Other Decks in Programming

Transcript

  1. CPU-Native Code C++ / C / Swift • Debugging is

    annoying • C interop is sometimes a pain (JNI, Swift/C++ interop is new) • C interop is sometimes not as free as you think (Java Native Interface) • Misses advantages of virtual machines with JIT (like the Android Runtime) • Can bloat binary size unnecessarily • Misses JIT-level optimizations (especially pro fi le guided optimizations)
  2. JavaScript • Debugging is painful • Performance characteristics can depend

    on the host VM • Misses platform-speci fi c optimizations • Interop overhead • “Smart View” problems
  3. Xamarin / Mono • Debugging is painful • Build-time complexity

    incorporating msbuild • Slow, generational stop-the-world GC • Misses advantages of platform-native virtual machines • ART pro fi le-guided optimizations • LLVM JIT negatively impacts startup performance, which is already bad
  4. int square(int num) { return num * num; } de

    fi %2 = alloca i32, align 4 store i32 %0, ptr %2, align 4 call void @llvm.dbg.declare(metadata ptr %2, metadata !16), !dbg !17 %3 = load i32, ptr %2, align 4, !dbg !18 %4 = load i32, ptr %2, align 4, !dbg !19 %5 = mul nsw i32 %3, %4, !dbg !20 ret i32 %5, !dbg !21 }
  5. int square(int num) { return num * num; } de

    fi ne dso_local noundef i32 @_Z6squarei(i32 noundef %0) #0 !dbg !10 { %2 = alloca i32, align 4 store i32 %0, ptr %2, align 4 call void @llvm.dbg.declare(metadata ptr %2, metadata !16), !dbg !17 %3 = load i32, ptr %2, align 4, !dbg !18 %4 = load i32, ptr %2, align 4, !dbg !19 %5 = mul nsw i32 %3, %4, !dbg !20 ret i32 %5, !dbg !21 }
  6. MODULE_FRAGMENT name:<main> FILE fqName:<root> fi FUN name:square visibility:public modality:FINAL <>

    (n:kotlin.Int) returnType:kotlin.Int VALUE_PARAMETER name:n index:0 type:kotlin.Int BLOCK_BODY RETURN type=kotlin.Nothing from='public fi CALL 'public fi $this: GET_VAR 'n: kotlin.Int declared in <root>.square' type=kotlin.Int origin=null other: GET_VAR 'n: kotlin.Int declared in <root>.square' type=kotlin.Int origin=null fun square(n: Int): Int { return n * n }
  7. MODULE_FRAGMENT name:<main> FILE fqName:<root> fi leName:sources/main.kt FUN name:square visibility:public modality:FINAL

    <> (n:kotlin.Int) returnType:kotlin.Int VALUE_PARAMETER name:n index:0 type:kotlin.Int BLOCK_BODY RETURN type=kotlin.Nothing from='public fi nal fun square (n: kotlin.Int): kotlin.Int declared in <root>' CALL 'public fi nal fun times (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int $this: GET_VAR 'n: kotlin.Int declared in <root>.square' type=kotlin.Int origin=null other: GET_VAR 'n: kotlin.Int declared in <root>.square' type=kotlin.Int origin=null fun square(n: Int): Int { return n * n }
  8. > Task :common:compileDebugKotlinAndroid FAILED e: Expected class ‘Platform' has no

    actual declaration in module <common_debug> for JVM expect class Platform {}
  9. • All Kotlin Common • Delegate to platforms with expect

    & actual • Glue for platform-native libraries • Application • Kotlin all the way down (Compose Multiplatform) • Library • For Kotlin Multiplatform • For platform targets (XCFramework, Android Archive, NPM Package) How What Lots of Options
  10. Some Good Third-Party Libraries • cashapp/SQLDelight • square/okio • ktorio/ktor

    • And a weird one (cashapp/ Redwood) • Kotlin/kotlinx.serialization • Kotlin/kotlinx-datetime • Kotlin/kotlinx-io • Kotlin/kotlinx.collections.immutable Some Good First Party Libraries
  11. Peril • N+1 Problem • Kotlin/Native doesn’t support vararg parameters

    - so Kotlin common is missing String.format. • Building JS-native NPM packages is onerous. • Sometimes you want (or need) API boundaries to be di ff erent between platform targets. Doable but a little awkward. • Pure Swift dependencies aren’t supported for Apple targets.
  12. common/ • Authentication initial password grant & refreshing access token

    • Network http & json serialization • Caching SQLite & simple key-value storage • Text processing HTML → platform-speci fi c rich text representations
  13. Directory Files Lines Blanks Comments Code Complexity Common 32 Kotlin

    971 148 8 815 64 knapsack- android 12 Kotlin 784 79 29 676 17 knapsack-iOS 10 Swift 442 76 68 298 10