Skip to content

Commit

Permalink
Add explicit scenarios for feature gate usage
Browse files Browse the repository at this point in the history
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 <vadossi@cosmonic.com>
  • Loading branch information
vados-cosmonic committed Aug 19, 2024
1 parent 4eb255f commit 29682a4
Showing 1 changed file with 158 additions and 7 deletions.
165 changes: 158 additions & 7 deletions design/mvp/WIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ interface a {
resource r;
}
interface b {
use a.{r};
use a.{r};
foo: func() -> r;
}
Expand Down Expand Up @@ -946,17 +946,21 @@ required to always be paired up with either a `@since` or `@deprecated` gate.
Together, these gates support a development flow in which new features start
with an `@unstable` gate while the details are still being hashed out. Then,
once the feature is stable (and, in a WASI context, voted upon), the
`@unstable` gate is switched to a `@since` gate. To enable a smooth transition
(during which producer toolchains are targeting a version earlier than the
`@since`-specified `version`), the `@since` gate contains an optional `feature`
field that, when present, says to enable the feature when *either* the target
version is greator-or-equal *or* the feature name is explicitly enabled by the
developer. Thus, `c` is enabled if the version is `0.2.2` or newer or the
`@unstable` gate is switched to a `@since` gate.

To enable a smooth transition (during which producer toolchains are targeting a
version earlier than the `@since`-specified `version`), the `@since` gate contains
an optional `feature` field that, when present, says to enable the feature when
*either* the target version is greater-or-equal *or* the feature name is explicitly
enabled by the developer.

Thus, `c` is enabled if the version is `0.2.2` or newer or the
`fancy-foo` feature is explicitly enabled by the developer. The `feature` field
can be removed once producer toolchains have updated their default version to
enable the feature by default.

Specifically, the syntax for feature gates is:

```wit
gate ::= gate-item*
gate-item ::= unstable-gate
Expand All @@ -973,6 +977,7 @@ version-field ::= 'version' '=' <valid semver>

As part of WIT validation, any item that refers to another gated item must also
be compatibly gated. For example, this is an error:

```wit
interface i {
@since(version = 1.0.1)
Expand All @@ -981,6 +986,7 @@ interface i {
type t2 = t1; // error
}
```

Additionally, if an item is *contained* by a gated item, it must also be
compatibly gated. For example, this is an error:
```wit
Expand All @@ -993,6 +999,151 @@ interface i {
}
```

#### Scenario: Stabilization of a new feature

This section lays out the basic flow and expected usage of feature gate machinery when stabilizing a new feature.

Assume the following WIT package as the initial interface:

```wit
package examples:fgates-calc@0.1.0;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@since(version = 0.1.0)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

**First, add new items under an `@unstable` annotation with a `feature` specified:**

```wit
package examples:fgates-calc@0.1.1;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@since(version = 0.1.0)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
/// By convention, feature flags should be prefixed with package name to reduce chance of collisions
///
/// see: https://github.com/WebAssembly/WASI/blob/main/Contributing.md#filing-changes-to-existing-phase-3-proposals
@unstable(feature = fgates-calc-minus)
sub: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

At this point, consumers of the WIT can enable feature `fgates-calc-minus` through their relevant tooling and get access to the `sub` function.

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.

**Second, when the feature is ready to be stabilized, switch to a `@since` annotation:**

```wit
package examples:fgates-calc@0.1.2;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@since(version = 0.1.0)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
@since(version = 0.1.2)
sub: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

#### Scenario: Deprecation of an existing stable feature

This section lays out the basic flow and expected usage of feature gate machinery when stabilizing a new feature.

Assume the following WIT package as the initial interface:

```wit
package examples:fgates-deprecation@0.1.1;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@since(version = 0.1.0)
add-one: func(x: i32) -> result<i32, calc-error>;
@since(version = 0.1.1)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

**First: Add the `@deprecated` annotation to the relevant item in a new version**

```wit
package examples:fgates-deprecation@0.1.2;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@deprecated(version = 0.1.2)
add-one: func(x: i32) -> result<i32, calc-error>;
@since(version = 0.1.1)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

At this point, tooling consuming this WIT will be able to appropriately alert users to the now-deprecated `add-one` function.

**Second: completely remove the deprecated item in the next SemVer-compliant major version**

```wit
package examples:fgates-deprecation@0.2.0;
@since(version = 0.1.0)
interface calc {
@since(version = 0.1.0)
variant calc-error {
integer-overflow,
integer-underflow,
unexpected,
}
@since(version = 0.1.1)
add: func(x: i32, y: i32) -> result<i32, calc-error>;
}
```

In this new "major" version (this is considered a major version under SemVer 0.X rules) -- the `add-one` function can be fully removed.

## Package declaration
[package declaration]: #package-declaration

Expand Down

0 comments on commit 29682a4

Please sign in to comment.