Skip to content

Commit 3a1d715

Browse files
authored
Merge pull request #174 from Mossaka/union
Add an `include` keyword
2 parents 9b1034c + 0820d22 commit 3a1d715

File tree

1 file changed

+165
-1
lines changed

1 file changed

+165
-1
lines changed

design/mvp/WIT.md

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,150 @@ Kebab names cannot overlap and must be unique, even between imports and exports.
236236
IDs, however, can be both imported and exported. The same interface cannot be
237237
explicitly imported or exported twice.
238238

239+
### Union of Worlds with `include`
240+
241+
A World can be created by taking the union of two or more worlds. This operation allows world builders to form larger worlds from smaller worlds.
242+
243+
Below is a simple example of a world that includes two other worlds.
244+
245+
```wit
246+
package local:demo
247+
248+
// definitions of a, b, c, foo, bar, baz are omitted
249+
250+
world my-world-a {
251+
import a
252+
import b
253+
export c
254+
}
255+
256+
world my-world-b {
257+
import foo
258+
import bar
259+
export baz
260+
}
261+
262+
world union-my-world {
263+
include my-world-a
264+
include my-world-b
265+
}
266+
```
267+
268+
The `include` statement is used to include the imports and exports of another World to the current World. It says that the new World should be able to run all components that target the included worlds and more.
269+
270+
The `union-my-world` World defined above is equivalent to the following World:
271+
272+
```wit
273+
world union-my-world {
274+
import a
275+
import b
276+
export c
277+
import foo
278+
import bar
279+
export baz
280+
}
281+
```
282+
283+
The `include` statement also works with [WIT package](#wit-packages-and-use) defined below with the same semantics. For example, the following World `union-my-world-a` is equivalent to `union-my-world-b`:
284+
285+
```wit
286+
package local:demo
287+
288+
interface b { ... }
289+
interface a { ... }
290+
291+
world my-world-a {
292+
import a
293+
import b
294+
import wasi:io/c
295+
export d: interface { ... }
296+
}
297+
298+
world union-my-world-a {
299+
include my-world-a
300+
}
301+
302+
world union-my-world-b {
303+
import a
304+
import b
305+
import wasi:io/c
306+
307+
export d: interface { ... }
308+
}
309+
```
310+
311+
### De-duplication of IDs
312+
313+
If two worlds shared the same set of import and export IDs, then the union of the two worlds will only contain one copy of this set. For example, the following two worlds `union-my-world-a` and `union-my-world-b` are equivalent:
314+
315+
```wit
316+
package local:demo
317+
318+
world my-world-a {
319+
import a1
320+
import b1
321+
}
322+
323+
world my-world-b {
324+
import a1
325+
import b1
326+
}
327+
328+
world union-my-world-a {
329+
include my-world-a
330+
include my-world-b
331+
}
332+
333+
world union-my-world-b {
334+
import a1
335+
import b1
336+
}
337+
```
338+
339+
### Name Conflicts and `with`
340+
341+
When two or more included Worlds have the same name for an import or export that does *not* have an ID, automatic de-duplication cannot be used (because the two same-named imports/exports might have different meanings in the different worlds) and thus the conflict has to be resolved manually using the `with` keyword:
342+
The following example shows how to resolve name conflicts where `union-my-world-a` and `union-my-world-b` are equivalent:
343+
344+
```wit
345+
package local:demo
346+
347+
world world-one { import a: func() }
348+
world world-two { import a: func() }
349+
350+
world union-my-world-a {
351+
include foo
352+
include bar with { a as b }
353+
}
354+
355+
world union-my-world-b {
356+
import a: func()
357+
import b: func()
358+
}
359+
```
360+
361+
`with` cannot be used to rename IDs, however, so the following world would be invalid:
362+
```wit
363+
package local:demo
364+
365+
interface a {
366+
foo: func()
367+
}
368+
369+
world world-using-a {
370+
import a
371+
}
372+
373+
world invalid-union-world {
374+
include my-using-a with { a as b } // invalid: 'a', which is short for 'local:demo/a', is an ID
375+
}
376+
377+
### A Note on SubTyping
378+
379+
In the future, when `optional` export is supported, the world author may explicitly mark exports as optional to make a component targeting an included World a subtype of the union World.
380+
381+
For now, we are not following the subtyping rules for the `include` statement. That is, the `include` statement does not imply any subtyping relationship between the included worlds and the union world.
382+
239383
## WIT Packages and `use`
240384
[use]: #wit-packages-and-use
241385
@@ -699,6 +843,7 @@ keyword ::= 'use'
699843
| 'import'
700844
| 'export'
701845
| 'package'
846+
| 'include'
702847
```
703848

704849
### Integers
@@ -763,7 +908,7 @@ Concretely, the structure of a world is:
763908
```ebnf
764909
world-item ::= 'world' id '{' world-items* '}'
765910
766-
world-items ::= export-item | import-item | use-item | typedef-item
911+
world-items ::= export-item | import-item | use-item | typedef-item | include-item
767912
768913
export-item ::= 'export' id ':' extern-type
769914
| 'export' interface
@@ -778,6 +923,25 @@ from the root of a component and used within functions imported and exported.
778923
The `interface` item here additionally defines the grammar for IDs used to refer
779924
to `interface` items.
780925

926+
## Item: `include`
927+
928+
A `include` statement enables the union of the current world with another world. The structure of an `include` statement is:
929+
930+
```wit
931+
include wasi:io/my-world-1 with { a as a1, b as b1 }
932+
include my-world-2
933+
```
934+
935+
```ebnf
936+
include-item ::= 'include' use-path
937+
| 'include' use-path 'with' '{' include-names-list '}'
938+
939+
include-names-list ::= include-names-item
940+
| include-names-list ',' include-names-item
941+
942+
include-names-item ::= id 'as' id
943+
```
944+
781945
## Item: `interface`
782946

783947
Interfaces can be defined in a `wit` file. Interfaces have a name and a

0 commit comments

Comments
 (0)