Stream: general

Topic: how to manage callbacks


view this post on Zulip nikomatsakis (Jun 27 2024 at 12:48):

Hi everyone,

I'm trying to setup a "callback" system to handle async computation. I was creating a variant of @Dirk Bäumer's calculator example in which the operands can also be variables:

interface types {
    // ...
    variant operand {
        integer(u32),
        variable(string),
    }
    // ...
}

To resolve the value of a variable requires a callback, which I setup like so:

interface types {
    // ...
    resource with-operand-value {
        value: func(value: u32);
    }
    // ...
}

in the world there is a function:

world calculator {
    use types.{operation, with-operand-value, with-calc-result};
        // ...
    import resolve-variable: func(name: string, wov: with-operand-value);
        // ...
}

and in my Rust code I have a struct ResolveOperandFuture that implements the GuestWithOperandValue trait -- the impl is pretty broken (it doesn't use the Waker) -- but that's not the question.

The question is, when I try to call this, I invoke resolve_variable like so...

            resolve_variable(&name, WithOperandValue::new(future.clone()));

and I get an error like

error[E0599]: no function or associated item named `new` found for struct `vscode::example::types::WithOperandValue` >
  --> src/lib.rs:49:55

Digging more into this, it seems there are two WithOperandValue structs defined, one for the "exported" resource and one for the "imported" resource.

How can I manage this situation?

Using WebAssembly for Extension Development.
Contribute to nikomatsakis/wasm-vscode-experiment development by creating an account on GitHub.
Contribute to nikomatsakis/wasm-vscode-experiment development by creating an account on GitHub.
Contribute to nikomatsakis/wasm-vscode-experiment development by creating an account on GitHub.

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:51):

Leaving aside the details of the above, the core question is...

Is there a way to define a resource that I implement from Rust and then pass to an imported function?

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:52):

I'm more interested in that question then in the best way to model async callbacks (given that direct suport for async is not yet available to me), but we could discuss that specific question in a different topic :)

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:53):

The tl;dr; is "no". An exported resource is a type that's exported and imports cannot revert to exported types

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:53):

I'm trying to think through how this might be modeled

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:53):

This feels like a pretty major limitation!

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:53):

I think you'd have to invert it to have calc return a resource

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

I was just going to say that

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:54):

where you'd have something like step() and it'd return "no I need this variable" and you feed it back in

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

I had half a mind to do that already but it felt unnatural

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

so I was hoping there was another option

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

OK.

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:54):

Due to the way resources all work out there's unfortunately not really another option

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

/me thinks

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:54):

there'd have to be a major redesign to how resources work at a fundamental level to enable imports to refer to exports

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:54):

it feels like I basically wind up modeling "poll"

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:55):

right

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:55):

and I have to move the "callback management" to the other side

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:55):

ok

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:55):

Alex Crichton said:

there'd have to be a major redesign to how resources work at a fundamental level to enable imports to refer to exports

I can sort of see why

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:55):

or at least, I can imagine it (not knowing the details)

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:55):

in particular I can see why it'd be simpler to only have the 'dependency edges' going in 1 direciton between components

view this post on Zulip nikomatsakis (Jun 27 2024 at 12:56):

OK, I'll try that, thanks @Alex Crichton

view this post on Zulip Alex Crichton (Jun 27 2024 at 12:56):

I think of it as a functor-like thing where every time you instantiate a component it creates brand new types for the exported types, so there's no way for the imports to refer to the future thing which will be the exported resource type

view this post on Zulip nikomatsakis (Jun 27 2024 at 13:10):

(it occurs to me I could also provide integer handles across the boundary, but now I'm straying into the topic I didn't want to discuss here)

view this post on Zulip Joel Dice (Jun 27 2024 at 13:47):

See also https://github.com/WebAssembly/component-model/issues/272 for a discussion of why this limitation exists.

The Component Model does not currently allow you to refer to exported types in imports, which feels asymmetric given that one can easily refer to imported types in exports. This becomes a practical...

view this post on Zulip Joel Dice (Jun 27 2024 at 13:48):

+1 to the integer handles idea; I think that's the best you can do currently if you want to provide a general-purpose callback mechanism.


Last updated: Dec 23 2024 at 13:07 UTC