jessewilson
06/15/2026, 7:46 PM@EagerInitialization is really handy and I would like a non-deprecated mechanism for eager set-up in Kotlin/Wasmjessewilson
06/15/2026, 7:50 PMcommonMain generated guest interface like this:
public interface Guest {
public fun sum(a: Long, b: Long): Long
}
In wasmWasiMain I’m generating a lateinit var that holds the singleton implementation of this service:
public var WasmoTesting.guest: WasmoTesting.Guest
get() = ...
set(value) = ...
Finally, in non-generated code I put my user-authored implementation in the generated var:
WasmoTesting.guest = object : WasmoTesting.Guest {
override fun sum(a: Long, b: Long): Long {
return a + b
}
}jessewilson
06/15/2026, 7:51 PM@EagerInitialization to trigger that:
@EagerInitialization
val initialize = run {
WasmoTesting.guest = object : WasmoTesting.Guest {
override fun sum(a: Long, b: Long): Long {
return a + b
}
}
}jessewilson
06/15/2026, 7:54 PMOleg Yukhnevich
06/16/2026, 7:10 AMjessewilson
06/16/2026, 11:18 AMOleg Yukhnevich
06/16/2026, 11:47 AMI need something that isn't deprecated to do eager initialization.AFAIK,
@EagerInitialization is the only way to do this currently. It's deprecated, true, but the annotation and its behavior will be preserved until a stable alternative appears. A number of libraries in the wild are already using it to get some kind of SPI in KMP. Probably, the most interesting and popular user of it is Ktor (on all targets except for JVM).
For now, you can follow "KT-63218 EagerInitialization use cases" and share your use case there.
And again, so far, the main use case for this annotation is SPI (KT-53056: Multiplatform equivalent of JVM's ServiceLoader), which is why I'm trying to understand your use case in more detail.jessewilson
06/16/2026, 11:58 AMjessewilson
06/16/2026, 11:58 AMOleg Yukhnevich
06/16/2026, 12:28 PMThere should be exactly one implementationYeah, specifically this case is also similar to expect-actual and "KT-79983 # API - Implementation separation(Dependancy Invervesion)". In a more general ServiceLoader approach, though different strategies could be desired, like: • "exactly one" - your use case, Ktor engines, etc • "at most one" - optional things, like logging or tracing backends • "at least one" - cryptography backends, where those could contribute different things, but without them, it will not work at all • "multiple" - different extensions or plugins (e.g., in Dokka or Gradle), interceptors, and so on. Of course, not all of those really need some special handling, as not all of them are very popular in the wild.
I believe a sufficiently smart linker could detect it during whole-program-analysisAnd yes, it should be possible to do this on a second compiler stage (e.g., "linking", klibs -> binary). So, thanks for one more use case! But I have a question: why do you want this instance set up implicitly/automatically at build time, rather than via an explicit call in your
main or other entry-point function?jessewilson
06/16/2026, 12:32 PMOleg Yukhnevich
06/16/2026, 12:40 PM@EagerInitialization in the Kotlin stdlib, and why you don't like it? 🙂jessewilson
06/16/2026, 1:33 PMjessewilson
06/16/2026, 1:33 PMjessewilson
06/16/2026, 1:33 PMjessewilson
06/16/2026, 1:34 PMjessewilson
06/16/2026, 1:35 PMjessewilson
06/16/2026, 1:38 PMGuest) and a lateinit var that the application layer needs to place the implementation in.
// SOMEBODY NEEDS TO SET THIS...
public lateinit var guest: WasmoTesting.Guest
// BEFORE THIS CALL IS EXECUTED
@WasmExport("wasmo:testing/wasmo-testing#sum")
private fun WasmoTesting_guest_sum(a: Long, b: Long): Long = guest.sum(a, b)jessewilson
06/16/2026, 1:39 PM@EagerInitialize to run an arbitrary initialization block.
@OptIn(ExperimentalStdlibApi::class)
@EagerInitialization
val initialize = run {
guest = object : WasmoTesting.Guest {
override fun sum(a: Long, b: Long): Long {
return a + b
}
}
}jessewilson
06/16/2026, 1:41 PMjessewilson
06/16/2026, 1:42 PMpublic val guest: WasmoTesting.Guest = ServiceLoaderThing.only<WasmoTesting.Guest>()Oleg Yukhnevich
06/16/2026, 2:47 PM@EagerInitialization, and if we have an SPI-like solution (like sweet-spi), your "guest impl" code will be like (instead of @EagerInitialization):
@ServiceProvider(WasmoTesting.Guest::class)
object GuestImpl: WasmoTesting.Guest { /*...*/ }
So, in a nutshell, it's really a "plugin system" where guest implementations are "plugins," and there are no entry points in them to initialize anything, as they are invoked by the "host". Strictly speaking, it's a plugin system inside of a plugin system!
Aaaaaand, it looks like for this kind of use case, or any other kind of "plugins", @EagerInitialization (or SPI) is the only way.
Thanks again!
P.S. I'm just trying to categorize different use cases for SPI-related machinery and understand what a good fit for Kotlin is, and what isn't, as many languages in the wild don't really have direct analogs of JDK ServiceLoader, and they live with it, more or less, fine. kodee floatingjessewilson
06/16/2026, 2:55 PMjessewilson
06/16/2026, 2:55 PMOleg Yukhnevich
06/16/2026, 2:57 PMjessewilson
06/16/2026, 2:58 PM@EagerInitialization!