Top-level JS error mappings
For functions that directly return a result, is the expectation that these map to the host-level error handling? This is mentioned briefly as a possibility for JS results in the JS API embedding explainer section.
The possibilities seem to be:
- Do nothing - the function called in JS just returns the tagged object -
{ tag: 'err', value: err_value } - Throw top-level errors directly - the function called in JS throws the top-level result object error when there is an error and returns the value directly. This seems like it is similar to the Promise situation as well? -
throw err_valueorreturn success_value. - Wrap top-level errors with a JS
Error- the function first wraps the error in a JS error class before throwing the error -throw new Error(err_value).
It seems at first glance like a first-class error wrapping would be a nice design to handle the host integration, but (2) and (3) are both quite limited.
throw value per (2) does work pretty consistently for any value, and retains the one to one properties of the component model, but then there is no way to throw a native JS error type, which may be seen as weird from a user point of view (despite the fact that throw { some: 'data' } gives the most structured type of error logs!).
(3) would result in all top-level error values running through JS toString semantics and is then lossy from a component model value perspective, so then perhaps leads to thinking more carefully about the exact toString semantics of all data types to possibly be less lossy and avoid the infamous [object Object] kind of outputs. Note that records and tuples is currently specified to give [object Record] so doesn't help there much either!
From a high-level perspective, if building code for JS you'd expect to be able to throw nice errors to JS, for some definition of nice.
On the lifting side, when a component calls an imported function that throws, should we try and implement symmetric behaviours?
Another option might be to do something like throw Object.assign(new Error(String(err_value)), { value: err_value }) where the value is attached as a property of the error so that it can always be retrieved manually or otherwise, then to possibly even maintain this check so that arbitrary errors can be constructed for a symmetrical lifting.
(sorry for the slow reply!) Good question. I had been thinking of something roughly in the direction of (3), but using a subclass of the native Error constructor (analogous to or perhaps even a subclass of WebAssembly.RuntimeError). This subclass could then add a payload property providing the result's error-case's payload.