Closed flagxor closed 5 years ago
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.
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)
Would sorted key order still work if we add a key?
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.
@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});
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
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.