Why does Kotlin/Wasm depend on the WasmGC and exception-handling proposals, and what are the practical consequences?
answer
- Core Wasm: no GC, no exceptions
- WasmGC = host-managed structs/arrays
- Exception-handling proposal = native throw/catch
- Avoids shipping a GC inside the module
- Needs modern runtimes; keeps target experimental
basics
~20 sKotlin objects need garbage collection and Kotlin code throws exceptions. Instead of bundling those features, Kotlin/Wasm uses new WebAssembly proposals so the runtime provides GC and exception handling. The cost is that only recent runtimes can run the output.
solid answer
~40 sCore Wasm (the MVP) has only linear memory and no managed heap or exceptions, so a language like Kotlin would otherwise have to ship its own GC and an exception emulation inside the module — bloating size and hurting performance. Kotlin/Wasm instead targets the **WasmGC** proposal (managed reference types and struct/array heap objects collected by the host GC) and the **exception-handling** proposal (native `throw`/`catch` tags). This keeps modules small and fast because the host's mature GC manages Kotlin objects and exceptions use native unwinding. The practical consequence: output requires runtimes that implement these proposals — modern Chromium/Firefox and current Node/Wasmtime. Older or restricted environments can't run it, which is a key adoption and deployment consideration and part of why the targets remain experimental.
go deeper
Knows Kotlin/Wasm needs newer Wasm features and only runs on modern runtimes.
Explains that WasmGC handles object memory and the EH proposal handles exceptions, avoiding a bundled GC.
Articulates the tradeoff (small/fast vs runtime requirements), host-GC interop benefits, and the link to experimental status.
Drives adoption decisions: validates runtime support across the fleet, weighs Kotlin/Wasm vs JS/Native, and plans for proposal-stabilization risk.
## Background: what core Wasm lacks The original WebAssembly **MVP** gives you: - a **linear memory** (one big byte array) and numeric types, - functions and a stack, - **no managed objects**, **no garbage collector**, and **no exceptions**. For a low-level language (C, Rust) that's fine — they manage memory manually and don't need GC. But **Kotlin** has: - a **garbage-collected object model** (classes, closures, collections), and - **exceptions** (`throw`, `try`/`catch`, `finally`). ## Option A (not chosen): bring your own runtime A language could compile its own **GC and exception machinery into linear memory** (this is how some early Wasm-targeting languages worked). Downsides: - **Larger binaries** (you ship a GC). - **Slower** and harder to integrate with the host GC (e.g. the browser's, which also manages JS/DOM objects), risking duplicated heaps and cross-heap cycles. ## Option B (Kotlin's choice): use the new proposals ### WasmGC The **WasmGC** proposal adds **managed reference types** and **heap types** (`struct`, `array`) that the **host runtime's garbage collector** manages. Kotlin objects become WasmGC structs, so: - No GC is shipped inside the module. - Kotlin objects and JS objects can be collected by the **same host GC**, easing interop and cycles. - Modules are **smaller and faster**. ### Exception handling The **exception-handling** proposal adds native Wasm constructs (exception **tags**, `throw`, and catching during unwinding). Kotlin's `throw`/`try`/`catch` map onto these instead of emulating control flow in linear memory. ## Practical consequences - **Runtime requirements**: the output only runs where both proposals are implemented — **modern browsers** (recent Chrome/Firefox; Safari support lagged for a while) and **current Node.js / standalone runtimes** like Wasmtime. Old environments simply fail to instantiate the module. - **Experimental status**: because these proposals were stabilizing across runtimes, Kotlin/Wasm itself stays experimental, with the `@ExperimentalWasmDsl` opt-in on the build. - **Deployment planning**: you must confirm your target runtimes support WasmGC + EH before shipping; this is a real go/no-go factor versus Kotlin/JS, which runs anywhere JS runs. - **Performance upside**: when supported, host-GC integration and native exceptions give Kotlin/Wasm competitive performance and small output. ## Quick mental model ```text Core Wasm: linear memory, no GC, no exceptions -> too low-level for Kotlin WasmGC: host-managed structs/arrays -> Kotlin objects, no bundled GC Exception-handling: native throw/catch tags -> Kotlin try/catch Result: small, fast modules but need a modern runtime ```
- Why does host-GC integration help interop specifically?Kotlin and JS objects can be managed by the same garbage collector, so references can cross the boundary and reference cycles between them can be collected without two competing heaps.
- How does this affect Safari or older browser support?Those engines were slower to ship WasmGC/EH, so Kotlin/Wasm output couldn't run there until support landed — a concrete reason to verify target runtimes before adopting.
Rather than packing your own generator (a bundled GC) into every shipment, Kotlin/Wasm plugs into the building's power grid (the host's WasmGC and exception support) — lighter, but only works in buildings that have the grid.
saying these in an interview costs you the question
- Saying Kotlin/Wasm bundles its own garbage collector into the module
- Claiming the output runs on any Wasm runtime including the MVP
- Thinking exceptions are emulated in linear memory in Kotlin/Wasm
- Ignoring runtime-support requirements when planning deployment
- Confusing WasmGC with the WASI system interface