Skip to content

Enhancement: generate Symbol.dispose on exported structs #4117

Closed
@H-Plus-Time

Description

@H-Plus-Time

Motivation

The end-goal is drop-in integration with the Explicit Resource Management proposal (at Stage 3), with the nearer term goal of smoothing integration with tools that polyfill that.

The syntax it enables:

const func = () => {
  // declare an instance of our wasm-bindgen'd struct, specifying that it should be cleaned up
  // at the end of the scope it's declared in.
  using foobar = new MyStruct();
  // do a bunch of stuff...
}
func();
// When func() (or any other scope that keyword is used in) finishes, MyStruct::free is called

At the moment, Deno, Bun and Typescript >= 5.2 support the above directly; Usage without the above sugar is a little underwhelming, but probably still useful as a standardized target:

class MyStruct {
  free() {} // the usual wasm-bindgen methods elided for brevity
  [Symbol.dispose]() {
    this.free();
  }
}

const foo = new MyStruct();
foo[Symbol.dispose]();
// or, more usefully, use a disposable stack (supplied by a polyfill) to orchestrate 
// more elaborate resource management
const stack = new DisposableStack();
const bar = stack.use(new MyStruct());
const baz = stack.use(new OtherStruct(bar));
// free the above in reverse order
stack[Symbol.dispose](); 

Proposed Solution

Include the [Symbol.dispose]() { this.free() } pattern on all generated classes, polyfilling via Symbol.dispose ??= Symbol("Symbol.dispose");.

Async dispose is probably irrelevant

Alternatives

It's not terribly difficult for 3rd party authors to run the generated bindings through code transformation of their own.

Additional Context

The ecmascript proposal, for reference: https://github.com/tc39/proposal-explicit-resource-management

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions