Skip to content
This repository was archived by the owner on Aug 17, 2022. It is now read-only.

Binding type for dicts #3

Closed
flagxor opened this issue Nov 10, 2017 · 6 comments
Closed

Binding type for dicts #3

flagxor opened this issue Nov 10, 2017 · 6 comments
Assignees

Comments

@flagxor
Copy link
Member

flagxor commented Nov 10, 2017

Passing in dicts is a common Web API pattern.
We should consider making this efficient.
We probably need to take into account the idea that several versions of the set of keys might exist.

@flagxor flagxor self-assigned this Nov 10, 2017
@lukewagner
Copy link
Member

In particular, while one would have the generic ability to create an object (through imported Object.create), store it into a Table<anyref>, and set properties on it (through imported Reflect.set), it might be useful to have the ability to efficiently express calls like foo({x:1, y:2}) by just passing the scalars (1, 2) since the implementation of the WebIDL binding might be able to take these scalars directly, avoiding object creation altogether.

One could imagine a compound argument/return host binding that says "create a dict with x set to the next i32 arg and y set to the next next i32 arg".

A rough sketch as to how this might look in C++ is:

// generated from .idl file:
template <class... Field> struct PASS_AS_SCALARS dict { ... };
template <class... Field> dict<FieldT...> make_dict(Field&&...);
struct WEBIDL_DICT_FIELD x { int32_t value; x(int32_t v) : value(v) {} };
struct WEBIDL_DICT_FIELD y { int32_t value; y(int32_t v) : value(v) {} };
template <class... Field> void WEBIDL_IMPORT foo(dict<Field...>);

// called like:
foo(make_dict(x(1), y(2)));

assuming WEBIDL_* macros map to some magic attribute syntax and PASS_AS_SCALARS ensures that dict values are passed as individual scalar fields in args instead of through linear memory. Something similar in C is probably achievable through fancy macros.

@magcius
Copy link

magcius commented Nov 11, 2017

How would that approach work for optional keys? e.g. you can do canvas.getContext('webgl', { antialias: false }) or canvas.getContext('webgl', { alpha: false }). We could require that all arguments are passed explicitly in some sort of sorted key order, but I don't believe there's an equivalent value to undefined right now in WASM. (The lack of a value that maps to undefined or equivalent in host bindings should probably be covered somehow by this spec, anyway)

@annevk
Copy link
Member

annevk commented Nov 11, 2017

Would sorted key order still work if we add a key?

@magcius
Copy link

magcius commented Nov 11, 2017

I misunderstood Luke's proposal. Something not clear to me in the spec is that you can import a binding multiple times with different annotations. Luke is suggesting some complex annotation syntax for dictionaries which corresponds to "construct a dictionary, the first argument is set to x, the second argument is set to y".

To handle optional keys, you import the binding multiple times with differing annotations.

This has the obvious downside that I can't specify whether a key is missing or not at runtime, but that might just be better off done by the Object.create / Reflect.set method.

@lukewagner
Copy link
Member

@magcius Exactly right. If a dict is being used to implement named+optional parameters, then there should probably be a small static set of imported signatures that were used for a given underlying WebIDL method that takes a dictionary. And also right that, as fallback, one could generate the dictionary dynamically, at some runtime cost.

@annevk Here we are not relying on any sort of static order; the binding is mapping parameters to (a subset of) dictionary key names.

Just as a concrete example, if the foo in my above example had the WebIDL signature:

dictionary args { a:double, b:double, x:long, y:long, z:double }
void foo(args);

you could write the following C++ (as described in my first comment):

foo(make_dict(x(1), a(2.0));
foo(make_dict(a(1.0), y(2), b(3.0));

and you'd get two wasm imports:

(import "" "foo" (func $foo1 (param i32) (param f64)))
(import "" "foo" (func $foo2 (param f64) (param i32) (param f64)))

and each would have a host binding (making up .wat syntax on the fly, so bear with me):

(binding $foo1 (dictionary (key "x") (key "a")))
(binding $foo2 (dictionary (key "a") (key "y") (key "b")))

and this would basically capture what in JS you'd write as:

foo({x:1, a:2});
foo({a:1, y:2, b:3});

@pchickey
Copy link
Collaborator

Closing as out-of-date: these concepts don't map to the current proposal, which has evolved a lot since this issue was opened. Some relevant discussion continues in #61

lukewagner added a commit that referenced this issue Nov 22, 2021
Generalize Module Types to Module Linking
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants