Stream: general

Topic: WIT binding for Kotlin/Wasm


view this post on Zulip Sébastien Deleuze (Feb 07 2023 at 07:47):

Kotlin/Wasm is an effort driven by the Kotlin team to introduce first class support for Wasm in Kotlin without generating JVM bytecode and by leveraging Wasm GC. I am collaborating with them to move forward Wasm Component Model binding and WASI support on https://github.com/sdeleuze/kowasm.

We have started to explore how WIT can be translated to Kotlin, see WitToKotlin.kt and the related comments. What is interesting with Kotlin is that it provides a more expressive language than Java, closer to what Rust allows in term of expressiveness, but higher level due to his GCed nature.

Please find below a summary of questions/remarks we have, and where we are looking for feedback:

KoWasm is an experimental project intended to provide WASI and WebAssembly Component Model support for Kotlin/Wasm - GitHub - sdeleuze/kowasm: KoWasm is an experimental project intended to provide ...
KoWasm is an experimental project intended to provide WASI and WebAssembly Component Model support for Kotlin/Wasm - kowasm/WitToKotlin.kt at main · sdeleuze/kowasm
See #2

view this post on Zulip Mossaka (Joe) (Feb 07 2023 at 08:35):

but union looks like a weird one where we struggle to find an elegant translation. It makes sense on Rust but I am wondering how other languages approach it.

Hey! I recently worked on Go bindings support for wit-bindgen. Speaking of union, variant, and enum types, Go as a language does not support any of these types. The way I did is to use struct to define these types. There are two fields inside the struct, one is Kind and another is Value of any type. Then, use Go's switch statement, I can simulate "pattern matching" feature that some other languages have, like rust.

For example, the following variant type will be generated as roughly

variant c2 {
   a(s32)
   b(s64)
   c(r)
}
type C2Kind int

const (
    C2KindA C2Kind = iota
    C2KindB
    C2KindR
)

type C2 struct {
    kind C2Kind
    val  any
}

In addition to the struct, the bindgen will also generate accessor methods to this struct, including constructor, getter, and setters.

Then in the guest code, I can do

switch myC2.Kind() {
case C2KindA:
    // do something with myC2.GetA()
case C2KindB:
    // do other things
default:
    panic("exhausted")
}

Hope this helps!

view this post on Zulip Dan Gohman (Feb 07 2023 at 13:17):

Kotlin has data classes that map nicely to WIT records but they imply some binary compatiblity issues. We could use regular classes but we would lose features like destructuring and have weaker semantic match with WIT. I am curious if binary compatibility is ensured in other language bindings when a field is added to a record to help us to make an educated choice.

I imagine most source languages won't be able to maintain this kind of binary compatibility.

The component model has a concept of [subtyping] which includes the ability to add fields to records, but I expect it won't usually be implemented with source-language concepts of binary compatibility. Instead, it'll be implemented with component-model-typesystem-aware linking.

[subtyping]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Subtyping.md

Repository for design and specification of the Component Model - component-model/Subtyping.md at main · WebAssembly/component-model

view this post on Zulip Dan Gohman (Feb 07 2023 at 13:18):

We have mapped WIT option to Kotlin null-safety (wrapper less approach idiomatic in Kotlin to express the presence or not of a value)

This sounds great! One question is: Do you have a way to handle option<option<T>>?

view this post on Zulip Dan Gohman (Feb 07 2023 at 13:23):

Where mutability had to be expressed, we have chosen to default to val (read-only) rather than var (mutable) even if this does not look like defined by WIT. Is it ok? Should WIT says something about mutability?

All types in wit (other than resources) are pass-by-value, so once a value is received from an interface, code can mutate it or do whatever it wants with the value because it has its own copy.

view this post on Zulip Lann Martin (Feb 07 2023 at 13:31):

A sealed class (or interface) is probably the most "idiomatic" translation of union, but it requires class wrappers for every variant

view this post on Zulip Lann Martin (Feb 07 2023 at 13:34):

Another common approach would be to have a class with a "type" (or similarly named) field plus a nullable getter/setter per variant

view this post on Zulip Joel Dice (Feb 07 2023 at 14:25):

(deleted)

view this post on Zulip Joel Dice (Feb 07 2023 at 14:34):

Sébastien Deleuze said:

For the Java binding generator, I treated it like a variant, generating names for each field, e.g. f0, f1...

I did the same for Java, although Dan's point about option<option<T>> is making me think it needs another look.

I think that's the right choice. That's on my TODO list for the Java generator.

IMHO, I don't think WIT should have anything to say about mutability for value types, although for resource handles it may be relevant. Value types have copy semantics in WIT, so once a component receives the data, it can do whatever it wants with it. In terms of code generation, I'd say do whatever feels idiomatic for the language.

This seems related to the mutability question, and again I'd say do whatever is idiomatic.

view this post on Zulip Sébastien Deleuze (Feb 07 2023 at 16:40):

Dan Gohman said:

We have mapped WIT option to Kotlin null-safety (wrapper less approach idiomatic in Kotlin to express the presence or not of a value)

This sounds great! One question is: Do you have a way to handle option<option<T>>?

I think for this possible but uncommon case we would generate a wrapper. Kotlin/JVM can typically use java.util.Optional<T> for that, but it is not available in Kotlin/Wasm, so we would generate a custom Optional<T> or similar wrapper for that case.

view this post on Zulip Sébastien Deleuze (Feb 07 2023 at 16:41):

Thanks everybody for your feedback, super useful.


Last updated: Oct 23 2024 at 20:03 UTC