Open guybedford opened 1 year ago
I totally agree. This also dovetails perfectly with the changes in #129 to keep Wit co-expressive with what you can write in an arbitrary .wasm
component (so that you can get a faithful Wit generated from an arbitrary component, whether or not that component was originally generated using Wit). In particular, with #129, there are two cases for the types that are referenced by a function:
typeidx
was introduced by a type export: in this case, the type definition would be defined out-of-line with the name of the export and referenced by name in the function typeresource
type (ensured by component validation): in this case, the type would be written in-line in the function type (using the extended syntax you're proposing here)I was imagining this being more of a sugar in the WIT syntax, than actually reflecting into the component, but that's interesting to hear if there might be overlap with the actual component representation.
Would be interesting to hear @alexcrichton's perspective on this as well.
The *.wit
tooling actually historically supported this but it was removed after what I thought was consensus that it shouldn't be supported for the primary reason that anonymous types like this typically can't be represented in target languages. Given how the component binary format is structured and validated today generating a *.wit
from a component is not possible, however, due to the inability for *.wit
to express anonymous types. That, to me, means that something should change.
I don't personally mind too much one way or another, but if the decision is to support anonymous types then I think that should also be coupled with a rough plan for bindings generation. I don't think the most naive solution, for example enum Type3 { ... }
in Rust, is a suitable because I don't think that anyone would actually want to use that and it would basically be an antipattern in *.wit
files.
Could this be treated as sugar for something like a macro expansion generation.
For example from:
func p: (param: record {
name: string,
value: option<string>
}) -> result<_, enum {
error-a,
error-b
}>
being automatically expanded as if one had written:
enum myinterface-p-error {
error-a,
error-b
}
record myinterface-p-param {
name: string,
value: option<string>
}
func p: (param: myinterface-p-param) -> result<_, myinterface-p-error>
This way types within the component model itself remain non-anonymous, while this is treated more as a WIT feature?
That makes sense to me yeah, and the follow-up from that would be to verify, at the binary layer, that all types are named unless they're primitives/lists/etc.
Ah, right, I keep forgetting about the bindings generation problems for fully general records and variants for many languages, thanks Alex. I like the idea of component validation additionally requiring that all such value types (iiuc, the list is: record
, variant
, union
, enum
, flags
?) are required to be exported (which is already necessarily required for resource
types) so that way component types are "in sync" with Wit on what's expressible such that you can render a Wit from a component. (This is also a conservative starting point, since we can always relax the validation requirements later.)
In that case, I think Wit should probably not offer the additional inline type syntactic sugar since it will be synthesizing a type name that will be semantically visible to the consumers of the component.
Not pressing by any means, more nice-to-have, but thought I'd post while I'm thinking about it.
Just like one can define an inline tuple or result, it could be useful to define inline definitions.
That is, instead of:
Writing:
Where the above could be internalized as sugar for some anonymous type naming scheme (ideally derived from the function and param name itself, as opposed to its structure).