Swivelgames opened issue #9595:
Feature
Provide an interface for deriving a ComponentFunc params original names
Benefit
Presently,
wasmtime
provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.Implementation
In order to maintain backwards compatibility, it could likely be something like a
param_names()
method.impl ComponentFunc pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_` Iterates over names of function parameters
Alternatives
There really doesn't seem to be one that's built-in to
wasmtime
. In order to grab the parameter names, I'd likely need to do something far more complex.Based on
wasm-tools
, though, it seems like the name of the params are preserved in the.wasm
, which is intriguing.To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.
Swivelgames edited issue #9595:
Feature
Provide an interface for deriving a ComponentFunc params original names
Benefit
Presently,
wasmtime
provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.Implementation
In order to maintain backwards compatibility, it could likely be something like a
param_names()
method.impl ComponentFunc pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_` Iterates over names of function parameters
Alternatives
There really doesn't seem to be one that's built-in to
wasmtime
. In order to grab the parameter names, I'd likely need to do something far more complex.Based on
wasm-tools
, though, it seems like the name of the params are preserved in the.wasm
, which is intriguing.To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.
```[tasklist]Tasks
~~~
Swivelgames edited issue #9595:
Feature
Provide an interface for deriving a ComponentFunc params original names
Benefit
Presently,
wasmtime
provides a number tools that can be leveraged for something that resembles Reflection, but the details for Function Parameters are lossy. Especially for more complex runtime parameter mapping, it would be great if the names of function parameters were preserved, and an interface provided for retrieving them.Implementation
In order to maintain backwards compatibility, it could likely be something like a
param_names()
method.impl ComponentFunc pub fn param_names(&self) -> impl ExactSizeIterator<Item = String> + '_` Iterates over names of function parameters
Alternatives
There really doesn't seem to be one that's built-in to
wasmtime
. In order to grab the parameter names, I'd likely need to do something far more complex.Based on
wasm-tools
, though, it seems like the name of the params are preserved in the.wasm
, which is intriguing.To my knowledge, ComponentFunc params are the entities that do not have some way of deriving their original names.
Swivelgames commented on issue #9595:
For what it's worth, my personal use-case for this is for a runtime tool that presents the parameter names.
That being said, assigning arguments to parameters via their names is supported by some popular languages, so preserving parameters names could potentially improve the ergonomics when using languages that support named arguments.
C# (Starting at v4)
csharp MethodName(arg1: 42, arg2: "Hello");
Kotlin
kotlin myFunction(arg1 = 42, arg2 = "Hello")
Python
python my_function(arg1=42, arg2="Hello")
PHP
php my_function(arg1: 42, arg2: "Hello");
Ruby
ruby my_function(arg1: 42, arg2: "Hello")
Swift
swift myFunction(arg1: 42, arg2: "Hello")
Other languages support named arguments too, like
R
,Scala
,Lisp
, and others, but I can't imagine they're high on the list of targets for WASM/WASI :sweat_smile:iirc, you can _technically_ do it in C++20 with gcc and clang, but I'm actually not 100% sure about that, and not sure how popular of a feature it is _if you can do it_.
bjorn3 commented on issue #9595:
Are param names part of the abi as opposed to just debuginfo?
Swivelgames commented on issue #9595:
That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.
In
wasi-parser
, for instance, they're represented by a Vector of(String, Type)
tuples. Inwasm-wave
, it has methods for bothparams
andparam_names
, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an
Vec<Option<String>>
or by their index if they're omitted.
Swivelgames deleted a comment on issue #9595:
That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.
In
wasi-parser
, for instance, they're represented by a Vector of(String, Type)
tuples. Inwasm-wave
, it has methods for bothparams
andparam_names
, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an
Vec<Option<String>>
or by their index if they're omitted.
Swivelgames commented on issue #9595:
@bjorn3 That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.
In
wasi-parser
, for instance, they're represented by a Vector of(String, Type)
tuples. Inwasm-wave
, it has methods for bothparams
andparam_names
, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an
Vec<Option<String>>
or by their index if they're omitted.
Swivelgames edited a comment on issue #9595:
@bjorn3 That's a good question. I'm not sure. I was actually digging into that earlier after I posted my most recent message.
In
wasi-parser
, for instance, they're represented by a Vector of(String, Type)
tuples. Inwasm-wave
, it has methods for bothparams()
andparam_names()
, similar to what I'm proposing here, with the caveat that it will return an empty iterable "if this WasmFunc impl does not support param names."I imagine there are cases where they're not included, but I think that's still manageable. They could easily be represented either by an
Vec<Option<String>>
or by their index if they're omitted.
bjorn3 commented on issue #9595:
I mean if they are not considered part of the ABI, different components may use different param names for the same function and thus if the host uses named function params derived from the component itself, it wouldn't work with some components even if they are supposed to be abi compatible. Only deriving the named function params that use host uses from a .wit file hard coded into the host would work fine in that case as if the .wit file changes you may need to change the host anyway and can update callers that use named function param at the same time without being affected by the choice of param names by the component that the host wants to load.
Swivelgames commented on issue #9595:
It looks like the serde serializer in
wasm-parser
also expects them, but omits the names if they're an empty string.And
wasm-encoder
expects them as well.These examples, of course, are being extracted from the
.wasm
file itself, not the.wit
(except maybewasm-encoder
).But I'm looking around to see if their inclusion is at least outlined in a spec somewhere. :thinking:
bjorn3 commented on issue #9595:
The fact that it is encoded in the wasm file doesn't mean that it is supposed to affect the abi. It could well be included just to make debugging easier.
Swivelgames commented on issue #9595:
It looks like they're specifically included in the _component-level_ ABI
Component-level type definitions are symmetric to core-level type definitions,
but use a completely different set of value types. Unlike [core:valtype
]
which is low-level and assumes a shared linear memory for communicating
compound values, component-level value types assume no shared memory and must
therefore be high-level, describing entire compound values./* ... */ functype ::= (func (param "<label>" <valtype>)* (result <valtype>)?) /* ... */
In this case they're referred to as "label"s.
They're also included in the Binary format:
functype ::= 0x40 ps:<paramlist> rs:<resultlist> => (func ps rs) paramlist ::= lt*:vec(<labelvaltype>) => (param lt)*
Where
labelvaltype
is the Label + Type:labelvaltype ::= l:<label'> t:<valtype> => l t
All _parameter labels_, result labels, record field labels, variant case labels, flag labels, enum case labels, component import names, component export names, instance import names and instance export names must be unique in their containing scope, considering two labels that differ only in case to be equal and thus rejected.
Swivelgames edited a comment on issue #9595:
It looks like they're specifically included in the _component-level_ ABI
Component-level type definitions are symmetric to core-level type definitions,
but use a completely different set of value types. Unlike [core:valtype
]
which is low-level and assumes a shared linear memory for communicating
compound values, component-level value types assume no shared memory and must
therefore be high-level, describing entire compound values./* ... */ functype ::= (func (param "<label>" <valtype>)* (result <valtype>)?) /* ... */
In this case they're referred to as "label"s.
They're also included in the Binary format:
functype ::= 0x40 ps:<paramlist> rs:<resultlist> => (func ps rs) paramlist ::= lt*:vec(<labelvaltype>) => (param lt)*
Where
labelvaltype
is the Label + Type:labelvaltype ::= l:<label'> t:<valtype> => l t label' ::= len:<u32> l:<label> => l (if len = |l|)
All _parameter labels_, result labels, record field labels, variant case labels, flag labels, enum case labels, component import names, component export names, instance import names and instance export names must be unique in their containing scope, considering two labels that differ only in case to be equal and thus rejected.
Swivelgames commented on issue #9595:
Here's another reference from the
canonical-abi/definitions.py
:tada:@dataclass class FuncType(ExternType): params: list[tuple[str,ValType]]
Swivelgames commented on issue #9595:
So it appears that they're part of the component-level ABI, but not the core-level ABI.
Swivelgames edited a comment on issue #9595:
Here's another reference from the
canonical-abi/definitions.py
:+1:@dataclass class FuncType(ExternType): params: list[tuple[str,ValType]]
bjorn3 commented on issue #9595:
I couldn't find anywhere where the param names are actually checked for equality. AFAICT they are ignored for the purpose of checking if two function types are equal and thus ABI compatible.
Swivelgames commented on issue #9595:
Indeed. It seems my use-case (simply getting the list of parameter names) is supported, but not the additional use-case of implementing host-language named parameters, at least not at the moment.
Swivelgames edited a comment on issue #9595:
Indeed. It seems my use-case (simply getting the list of parameter names of a Component-level function at runtime) is supported, but not the additional use-case of implementing host-language named parameters, at least not at the moment.
Swivelgames edited a comment on issue #9595:
Indeed. It seems my use-case (simply getting the list of parameter names of a Component-level function at runtime) is supported, but not the additional use-case of implementing host-language named parameters (at least not for the moment).
Last updated: Dec 23 2024 at 12:05 UTC