Skip to content

Commit 41bef2a

Browse files
vados-cosmoniclukewagner
authored andcommitted
Add explicit scenarios for feature gate usage
This commit addds some explanation of the intended usage pattern of feature gates in order to make the transition points and functionality easier to identify/reason about. Signed-off-by: Victor Adossi <[email protected]>
1 parent dd6bfde commit 41bef2a

File tree

1 file changed

+164
-9
lines changed

1 file changed

+164
-9
lines changed

design/mvp/WIT.md

Lines changed: 164 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ interface a {
643643
resource r;
644644
}
645645
interface b {
646-
use a.{r};
646+
use a.{r};
647647
foo: func() -> r;
648648
}
649649
@@ -946,33 +946,36 @@ required to always be paired up with either a `@since` or `@deprecated` gate.
946946
Together, these gates support a development flow in which new features start
947947
with an `@unstable` gate while the details are still being hashed out. Then,
948948
once the feature is stable (and, in a WASI context, voted upon), the
949-
`@unstable` gate is switched to a `@since` gate. To enable a smooth transition
950-
(during which producer toolchains are targeting a version earlier than the
951-
`@since`-specified `version`), the `@since` gate contains an optional `feature`
952-
field that, when present, says to enable the feature when *either* the target
953-
version is greator-or-equal *or* the feature name is explicitly enabled by the
954-
developer. Thus, `c` is enabled if the version is `0.2.2` or newer or the
949+
`@unstable` gate is switched to a `@since` gate.
950+
951+
Thus, `c` is enabled if the version is `0.2.2` or newer or the
955952
`fancy-foo` feature is explicitly enabled by the developer. The `feature` field
956953
can be removed once producer toolchains have updated their default version to
957954
enable the feature by default.
958955

959-
Specifically, the syntax for feature gates is:
956+
#### Feature gate syntax
957+
958+
The grammar that governs feature gate syntax is:
959+
960960
```wit
961961
gate ::= gate-item*
962962
gate-item ::= unstable-gate
963963
| since-gate
964964
| deprecated-gate
965965
966966
unstable-gate ::= '@unstable' '(' feature-field ')'
967-
since-gate ::= '@since' '(' version-field ( ',' feature-field )? ')'
967+
since-gate ::= '@since' '(' version-field ')'
968968
deprecated-gate ::= '@deprecated' '(' version-field ')'
969969
970970
feature-field ::= 'feature' '=' id
971971
version-field ::= 'version' '=' <valid semver>
972972
```
973973

974+
#### Rules for feature gate usage
975+
974976
As part of WIT validation, any item that refers to another gated item must also
975977
be compatibly gated. For example, this is an error:
978+
976979
```wit
977980
interface i {
978981
@since(version = 1.0.1)
@@ -981,6 +984,7 @@ interface i {
981984
type t2 = t1; // error
982985
}
983986
```
987+
984988
Additionally, if an item is *contained* by a gated item, it must also be
985989
compatibly gated. For example, this is an error:
986990
```wit
@@ -993,6 +997,157 @@ interface i {
993997
}
994998
```
995999

1000+
The following rules apply to the use of feature gates:
1001+
1002+
- Either `@since` *or* `@unstable` should be used, but not both (exclusive or).
1003+
- If a package contains a feature gate, it's version must be specified (i.e. `namespace:[email protected]`)
1004+
1005+
#### Scenario: Stabilization of a new feature
1006+
1007+
This section lays out the basic flow and expected usage of feature gate machinery
1008+
when stabilizing new features and deprecating old ones.
1009+
1010+
Assume the following WIT package as the initial interface:
1011+
1012+
```wit
1013+
package examples:[email protected];
1014+
1015+
@since(version = 0.1.0)
1016+
interface calc {
1017+
@since(version = 0.1.0)
1018+
variant calc-error {
1019+
integer-overflow,
1020+
integer-underflow,
1021+
unexpected,
1022+
}
1023+
1024+
@since(version = 0.1.0)
1025+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1026+
}
1027+
```
1028+
1029+
**First, add new items under an `@unstable` annotation with a `feature` specified:**
1030+
1031+
```wit
1032+
package examples:[email protected];
1033+
1034+
@since(version = 0.1.0)
1035+
interface calc {
1036+
@since(version = 0.1.0)
1037+
variant calc-error {
1038+
integer-overflow,
1039+
integer-underflow,
1040+
unexpected,
1041+
}
1042+
1043+
@since(version = 0.1.0)
1044+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1045+
1046+
/// By convention, feature flags should be prefixed with package name to reduce chance of collisions
1047+
///
1048+
/// see: https://github.com/WebAssembly/WASI/blob/main/Contributing.md#filing-changes-to-existing-phase-3-proposals
1049+
@unstable(feature = fgates-calc-minus)
1050+
sub: func(x: i32, y: i32) -> result<i32, calc-error>;
1051+
}
1052+
```
1053+
1054+
At this point, consumers of the WIT can enable feature `fgates-calc-minus` through their relevant tooling and get access to the `sub` function.
1055+
1056+
Note that, at least until subtyping is relaxed in the Component Model, if we had to *add* a new case to `calc-error`, this would be a *breaking change* and require either a new major version or adding a second, distinct `variant` definition used by new functions.
1057+
1058+
**Second, when the feature is ready to be stabilized, switch to a `@since` annotation:**
1059+
1060+
```wit
1061+
package examples:[email protected];
1062+
1063+
@since(version = 0.1.0)
1064+
interface calc {
1065+
@since(version = 0.1.0)
1066+
variant calc-error {
1067+
integer-overflow,
1068+
integer-underflow,
1069+
unexpected,
1070+
}
1071+
1072+
@since(version = 0.1.0)
1073+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1074+
1075+
@since(version = 0.1.2)
1076+
sub: func(x: i32, y: i32) -> result<i32, calc-error>;
1077+
}
1078+
```
1079+
1080+
#### Scenario: Deprecation of an existing stable feature
1081+
1082+
This section lays out the basic flow and expected usage of feature gate machinery when stabilizing a new feature.
1083+
1084+
Assume the following WIT package as the initial interface:
1085+
1086+
```wit
1087+
package examples:[email protected];
1088+
1089+
@since(version = 0.1.0)
1090+
interface calc {
1091+
@since(version = 0.1.0)
1092+
variant calc-error {
1093+
integer-overflow,
1094+
integer-underflow,
1095+
unexpected,
1096+
}
1097+
1098+
@since(version = 0.1.0)
1099+
add-one: func(x: i32) -> result<i32, calc-error>;
1100+
1101+
@since(version = 0.1.1)
1102+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1103+
}
1104+
```
1105+
1106+
**First: Add the `@deprecated` annotation to the relevant item in a new version**
1107+
1108+
```wit
1109+
package examples:[email protected];
1110+
1111+
@since(version = 0.1.0)
1112+
interface calc {
1113+
@since(version = 0.1.0)
1114+
variant calc-error {
1115+
integer-overflow,
1116+
integer-underflow,
1117+
unexpected,
1118+
}
1119+
1120+
@deprecated(version = 0.1.2)
1121+
add-one: func(x: i32) -> result<i32, calc-error>;
1122+
1123+
@since(version = 0.1.1)
1124+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1125+
}
1126+
```
1127+
1128+
At this point, tooling consuming this WIT will be able to appropriately alert users to the now-deprecated `add-one` function.
1129+
1130+
**Second: completely remove the deprecated item in some future SemVer-compliant major version**
1131+
1132+
```wit
1133+
package examples:[email protected];
1134+
1135+
@since(version = 0.1.0)
1136+
interface calc {
1137+
@since(version = 0.1.0)
1138+
variant calc-error {
1139+
integer-overflow,
1140+
integer-underflow,
1141+
unexpected,
1142+
}
1143+
1144+
@since(version = 0.1.1)
1145+
add: func(x: i32, y: i32) -> result<i32, calc-error>;
1146+
}
1147+
```
1148+
1149+
In this new "major" version (this is considered a major version under SemVer 0.X rules) -- the `add-one` function can be fully removed.
1150+
9961151
## Package declaration
9971152
[package declaration]: #package-declaration
9981153

0 commit comments

Comments
 (0)