| RFC-0231: FIDL versioning replacement syntax ||
|---|---|
| Status | Accepted |
| Areas | - FIDL |
| Description | Add a replaced=N argument to the @available attribute |
| Issues | - [135676](https://fxbug.dev/135676) |
| Gerrit change | - [922341](https://fuchsia-review.googlesource.com/c/fuchsia/+/922341) |
| Authors | - [mkember@google.com](https://fuchsia-review.googlesource.com/q/owner:mkember@google.com) |
| Reviewers | - [abarth@google.com](https://fuchsia-review.googlesource.com/q/owner:abarth@google.com) - [hjfreyer@google.com](https://fuchsia-review.googlesource.com/q/owner:hjfreyer@google.com) - [ianloic@google.com](https://fuchsia-review.googlesource.com/q/owner:ianloic@google.com) - [ddorwin@google.com](https://fuchsia-review.googlesource.com/q/owner:ddorwin@google.com) |
| Date submitted (year-month-day) | 2023-09-26 |
| Date reviewed (year-month-day) | 2023-10-24 |

[Edit this RFC](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md)
[Edit RFC metadata](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/contribute/governance/rfcs/_rfcs.yaml&searchAndJump=-+name:+'RFC-0231')

> [!NOTE]
> **Note:** This RFC is an amendment to [RFC-0083: FIDL versioning](https://fuchsia.dev/docs/contribute/governance/rfcs/0083_fidl_versioning).

## Summary

Change FIDL's `@available` attribute to support a `replaced` argument. It is
like `removed`, but validates that a replacement is `added` at the same version.

## Background

[RFC-0083: FIDL versioning](https://fuchsia.dev/docs/contribute/governance/rfcs/0083_fidl_versioning) introduced the `@available` attribute for
versioning FIDL APIs. One requirement in that design was to allow versioning all
possible changes. In other words, it should be possible to express `v1.fidl`
transitioning to an arbitrarily different `v2.fidl` in a single `versioned.fidl`
file. The design satisfied that requirement by allowing multiple elements to
have the same name as long as their version ranges don't overlap.

For example, consider adding the `@discoverable` attribute to protocol `P` at
version 5. We can't express this directly with `@available`, since attributes
can't be placed on other attributes. However, we can instead do this:

    @available(added=1, removed=5)
    protocol P {};

    @available(added=5)
    @discoverable
    protocol P {};

This technique of removing an element and re-adding it at the same version is
known as [swapping](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/reference/fidl/language/versioning.md;l=189;drc=818df65453cad51dd8351cd88074d606a00575e8).

## Motivation

The syntax for the usual lifecycle of adding, deprecating, and removing APIs is
intuitive. The swapping pattern, on the other hand, is not. It makes sense when
explained, but it is a hidden feature that requires explanation. In the [example
above](https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax#background), you'd be forgiven for thinking `removed=5` really means the
protocol is gone in version 5, especially if the corresponding `added=5` is not
adjacent in the source code.

Distinguishing replacement from removal also makes it possible to get rid of the
[legacy](https://fuchsia.dev/docs/reference/fidl/language/versioning#legacy) feature and replace it with a more general solution. This is a separate
proposal: [RFC-0232: FIDL bindings for multiple API levels](https://fuchsia.dev/docs/contribute/governance/rfcs/0232_fidl_bindings_for_multiple_api_levels).

## Stakeholders

*Facilitator:* abarth@google.com

*Reviewers:* hjfreyer@google.com, ianloic@google.com, ddorwin@google.com

*Consulted:* wez@google.com, sethladd@google.com, wilkinsonclay@google.com

*Socialization:* I discussed this idea with the FIDL team and the Platform
Versioning working group before writing the RFC.

## Design

- Introduce a new `@available` argument named `replaced`. It behaves the same as
  `removed` except it has different validation, described below. It can be
  used instead of `removed` on any element except the `library` declaration.

- When an element is marked `removed=N`, validate that there **IS NOT** another
  element with the same name marked `added=N`.

- When an element is marked `replaced=N`, validate that there **IS** another
  element with the same name marked `added=N`.

- This validation only applies to elements that are directly marked `removed` or
  `replaced`, not to child elements that [inherit](https://fuchsia.dev/docs/reference/fidl/language/versioning#inheritance) the arguments.

### Examples

The example from the [Background section](https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md.txt#background) of adding `@discoverable`
to a protocol at version 5 looks like this in the new design:

    @available(added=1, replaced=5)
    protocol P {};

    @available(added=5)
    @discoverable
    protocol P {};

As another example, consider replacing a struct that contains a member with an
anonymous type:

    @available(added=1, replaced=2)
    struct Foo {
        bar @generated_name("Bar") table {};
    };

    @available(added=2)
    struct Foo {
        baz string;
    };

Since the first `Foo` is marked `replaced=2`, fidlc validates that there is
another `Foo` marked `added=2`. However, it does *not* perform similar
validation for the child element `bar`, nor for its anonymous type `Bar`.

## Implementation

1. Implement the `replaced` argument, including its validation.

2. Change all FIDL files to use `replaced` instead of `removed` when applicable.

3. Implement the new `removed` validation. CQ will fail if (2) missed anything.

## Performance

This proposal has no impact on performance.

## Ergonomics

This proposal makes the [swapping](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/reference/fidl/language/versioning.md;l=189;drc=818df65453cad51dd8351cd88074d606a00575e8) pattern more ergonomic by directly supporting
it in the language.

## Backwards compatibility

This proposal has no impact on backwards compatibility.

## Security considerations

This proposal has no impact on security.

## Privacy considerations

This proposal has no impact on privacy.

## Testing

This following files must be updated to test the new behavior:

- tools/fidl/fidlc/tests/availability_interleaving_tests.cc
- tools/fidl/fidlc/tests/decomposition_tests.cc
- tools/fidl/fidlc/tests/versioning_tests.cc
- tools/fidl/fidlc/tests/versioning_types_tests.cc

## Documentation

The following pages must be updated to document `replaced`:

- [FIDL attributes](https://fuchsia.dev/docs/reference/fidl/language/attributes)
- [FIDL versioning](https://fuchsia.dev/docs/reference/fidl/language/versioning)
- [Fuchsia API evolution guidelines](https://fuchsia.dev/docs/development/api/evolution)

The term "swapping" should also be removed in favor of "replaced".

The [fidldoc](https://cs.opensource.google/fuchsia/fuchsia/+/main:/tools/fidl/fidldoc/README.md) tool currently operates on the JSON IR for a single API level, so
it never sees `removed` arguments, and will not see `replaced` either
(https://fxbug.dev/42084086). When this is fixed, fidldoc should be updated to
clearly indicate when something is replaced as opposed to removed.

## Drawbacks, alternatives, and unknowns

### Alternative: Re-added argument

This proposal introduces the `replaced` argument, which makes it clear when an
element is being replaced rather than removed. It prevents the scenario, "I
thought I couldn't use this API because it says `removed=5` and we target 6."

We could similarly introduce a `re_added` argument to clarify when an element is
added as a replacement rather than being added for the first time. It would
prevent the scenario, "I thought I couldn't use this API yet because it says
`added=6` and we target 5."

I rejected this alternative for a few reasons:

- I believe the first scenario is more important than the second.

- The name `re_added` is unsatisfactory, and I couldn't think of a better one.

- Even without this, we can still make [fidldoc](https://cs.opensource.google/fuchsia/fuchsia/+/main:/tools/fidl/fidldoc/README.md) infer whether an element is
  `added` for the first time or not.

## Prior art and references

I discussed a similar idea in 2021 while developing FIDL versioning, in an
internal document titled "FIDL versioning: Swapping elements".

This proposal is very specific to the design of FIDL versioning, so there is no
prior art on this exact problem, as far as I know.
[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/contribute/governance/rfcs/0231_fidl_versioning_replacement_syntax.md "Edit the source code of this page")