nicholasjackson/wasp

wondering how i can make an interface be respected on both sides?

gedw99 opened this issue · 1 comments

The current examples btw work for me.

The WASM runtime has an ABI which is a low level API, and you have made a golang WASI ABI.
For example the golang plugin has:

//export call_me
func callMe(in abi.WasmString) abi.WasmString

But if i wanted the golang main executable to have an interface and wanted the WASM modules to implement that interface, how would i do that ? The only way i know currently would be to use protobufs which can be done at runtime using proto reflect or compile time using a custom code generator.
SO, i am curious if you have any plans towards something similar to make this "design by contract" approach ?

Maybe this is the same as what your are referring to in the roadmap at the bottom of the Readme where it says "Ability to define custom ABIs for plugins, currently this is hard coded" ?

So the WASM module can't really implement an interface as is really a package in Go terms, not a struct, it can only import external functions.

You can however define the functions that should be imported as a package, I started to sketch this out here with the base ABI for the plugin interface that defines the string functions and memory allocations.

https://github.com/nicholasjackson/wasp/tree/main/go-abi

I started to build similar packages for AssemblyScript and Rust, my eventual plan is that these the end-user would be able to consume these using a standard package manager.

| Maybe this is the same as what your are referring to in the roadmap at the bottom of the Readme where it says "Ability to define custom ABIs for plugins, currently this is hard coded" ?

What I was kind of thinking here is that instead of doing ...

cb := &engine.Callbacks{}
cb.AddCallback("plugin", "call_me", callMe)

I could improve the UX on this by using some reflection so more like...

//go:generate go run gen.go

type MyABI() struct {}

// CallMe can be imported by the Wasm module and prints the string passed to it
// to StdOut
// generate name call_me
func (m*MyABI) CallMe(something string) {
  fmt.Println(something
}

err := e.RegisterPlugin("test", *plugin, myABI, nil)

If something like this was setup then I could add a command that would code generate the import for the module for example.

go generate ./file.go -lang=go

This would export a file that could then be imported by your wasm module, for example in Go you would get

//export call_me
func callMe(in abi.WasmString) abi.WasmString

However, if the lang was AssemblyScript

@external("env", "call_me")
export declare function call_me(inRaw: ArrayBuffer): ArrayBuffer;

Still trying to figure these things out, the best way I find is to create a real-world implementation, that generally uncovers pain points fast. @eveld and I have been building a Discord bot that uses WebAssembly modules and Wasp to dog food the API. It has actually been super helpful. I`ve been a little sidetracked recently as I have been working on a presentation for next week but I will be getting back on this in a few days.