Closed Mossaka closed 1 year ago
What you've outlined looks all good to me, although one more case to consider is type definitions in worlds:
world foo {
type a = u32;
}
world bar {
type a = u32;
}
world baz {
include self.foo;
include self.bar; // should this error?
}
I think the answer is "yes" it should error which would require the disambiguation syntax you've proposed to resolve.
I also think that https://github.com/WebAssembly/component-model/pull/164 makes the disambiguation syntax nicer here since there's only one namespace to disambiguate and you don't have to specify either imports or exports.
@Mossaka Really nice writeup, thanks! This generally looks great to me too.
@alexcrichton I might be missing something here but, in the exact case you give where both the name and structural type are the same, what's the problem with saying "these are the same" and de-duping, so that there is no error? To my understanding, this is analogous to the de-duping of two imports of the same interface.
There is an additional subtlety concerning exports. If we think of include
as meaning "I'd like to define a new world that is able to run all components targeting the included world and more", then, if we define include
as simply unioning the exports (symmetric to how you've shown include
as unioning the imports), then a component targeting the included world won't be a subtype of the unioned world (b/c it won't have any exports that were subsequently added). To properly solve this, we need optional
exports, which would let us say: if an export isn't present in all include
d worlds, it is optional
. With this definition of include
, a component targeting an included world would indeed be a subtype of the union world. In the short term, I expect we could get away with simply defining include
to take the union of exports (just like imports) and having host bindings implicitly interpret all exports as optional. Eventually this stopgap will break down in more-advanced composition scenarios, but I'm hoping those don't arise in the Preview2 timeframe so we don't have to add optional
quite yet.
(Btw: lest the asymmetry bother anyone: if we think of the dual operation of world "intersections" (e.g., if I want to build a single component that can successfully run in multiple unrelated worlds), then above rules just get flipped between imports/exports: imports are optional
if not in all worlds; exports are simply unioned.)
Thank you, @alexcrichton and @lukewagner for your comments!
I also think that https://github.com/WebAssembly/component-model/pull/164 makes the disambiguation syntax nicer here since there's only one namespace to disambiguate and you don't have to specify either imports or exports.
This is really nice!
To my understanding, this is analogous to the de-duping of two imports of the same interface.
I was thinking the same. Maybe it makes more sense for the following type definitions in worlds to be resolved using with
world foo {
type a = u64;
}
world bar {
type a = u32;
}
world baz {
include self.foo with { a as a1}
include self.bar;
}
a component targeting the included world won't be a subtype of the unioned world
Ah right, it will break the subtyping rule if we are not careful about union-ing exports. Good point! I agree that for now we can let the host to implicitly treat all exports as optional.
That's true yeah, although the subtyping/equality check is currently only present in the wasm binary validator rather than the WIT parser phase, so I'd be tempted to say that to be conservative as a starting point types are required to be disambiguated and perhaps in the future we can relax the rule for structurally equivalent types.
Otherwise though @Mossaka yeah I think the syntax works the same with similar semantics, it's just that types are something to consider in addition to named interfaces/functions.
so I'd be tempted to say that to be conservative as a starting point types are required to be disambiguated and perhaps in the future we can relax the rule for structurally equivalent types.
That makes sense. For now, let's disambiguate type defs even though structurally they are equivalent. In this case, does my de-duplication section still makes sense? It might need to check if the duplicated types have the same structures which is equivalent to subtyping/equality check in WIT parser phase.
Yeah what you mentioned makes sense to me which is to always require explicit renaming on conflicts.
I think this is resolved by #174 (but please reopen if there is still more to the proposal to be done).
I want to raise this issue to propose a new syntax for the union of Worlds. The primary motivation for this proposal is that we want to be able to form a more compresive world by unionizing / combining multiple worlds together to form a bigger one. Concretly, this is motivated by the
wasi-cloud-core
proposal, which tries to define a new World that includes all the wasi-cloud worlds as to provide a feature set that allows a serverless / edge function to do state management or message exchanging.Proposal
This proposal adds a new syntax
include <world-path>
in World definition. Below are a few examples/sketches showing how theinclude
syntax would work.Union of two Worlds
Include a World that has package and inline imports
Name Conflicts
This is a more challenging example where the two Worlds being included have name conflicts. The solution to this is to use
with
syntax and aliasing to avoid conflicts of names. Thewith
syntax is only used to avoid name conflicts for those names that are in conflict with another World. The names that are not in conflicts should stay the same and need not to be specified in thewith
scope.De-duplication
Let me know your thoughts on this design! @lukewagner @fibonacci1729 @alexcrichton