# Gating API on editions

**URL:** <https://internals.rust-lang.org/t/gating-api-on-editions/12178>\
**Category:** language design\
**Created:** [April 17, 2020, 2:00pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178 "2020-04-17T14:00:56Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 2:00pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/1 "2020-04-17T14:00:56Z")

</div>

> [@2021 edition?](https://internals.rust-lang.org/t/2021-edition/12153/35):
>
> (At least currently,) library changes can't be gated on editions,

## Idea 1: pub (..edition)

```rust
pub (..2018) fn foo() {..}
pub (2021..) fn bar() {..}

```

would a restriction on which items are considered public depending on edition solve this?

## Idea 2: std features

`editions => features` in `std`-aware `cargo`?

Concern: `2018` and `202a` crates shouldn't see conflicting `impl`-s of a `trait`, etc. But these issues should already exist when features drive conditional compilation today..

## Update

This is a spin-off from [2021 edition](https://internals.rust-lang.org/t/2021-edition/12153/45) topic; one of the ideas discussed was if a hypothetical `202a` edition could not only remove deprecated syntax but also deprecated API-s.

Indeed there is a lot less motivation to have this outside of std. As suggested bellow new syntax can easily be replaced by unstable attributes.

Whichever syntax used the idea was to discuss a possible implementation path: either tweaks to visibility (`pub`) or conditional compilation in `std`-aware `cargo`.

Apologies for initial excessive brevity and lack of clarity.

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 17, 2020, 2:16pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/2 "2020-04-17T14:16:56Z")

</div>

What about something based on configurations instead?

```rust
#[cfg(edition="..2018")] pub fn foo() {..};
#[cfg(edition="2020..")] pub fn bar() {..};

```

You could also use this to create chains of 'if-else' statements, which will let you panic if the edition is unexpected.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 2:18pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/3 "2020-04-17T14:18:07Z")

</div>

> [@ckaran](#):
>
> What about something based on configurations instead?

That's almost exactly what I meant by "Idea 2" above

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [April 17, 2020, 2:27pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/4 "2020-04-17T14:27:50Z")

</div>

Who would use this feature? The only "customer" I can think of is the stdlib, and even then I'm not 100% convinced this is useful (because the stdlib still has to support all editions).

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 17, 2020, 2:27pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/5 "2020-04-17T14:27:56Z")

</div>

I see, I didn't understand what you meant.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 2:29pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/6 "2020-04-17T14:29:09Z")

</div>

> [@mjbshaw](#):
>
> Who would use this feature? The only "customer" I can think of is the stdlib, and even then I'm not 100% convinced this is useful (because the stdlib still has to support all editions).

Yes this is an attempt to design a mechanism to allow API-s to be "removed" from STD in future editions

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 17, 2020, 2:31pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/7 "2020-04-17T14:31:07Z")

</div>

This was born from the discussion on [2021 edition?](https://internals.rust-lang.org/t/2021-edition/12153), which @atagunov referenced by his quote of @CAD97. That discussions seems to have spawned some new ideas, and (I think) @atagunov realized that since we were moving away from the topics subject in [2021 edition?](https://internals.rust-lang.org/t/2021-edition/12153) that it would be better to create a new topic (@atagunov, please correct me if I'm wrong).

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 17, 2020, 4:52pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/8 "2020-04-17T16:52:43Z")

</div>

We couldn't actually remove the APIs, since we still support the old editions. And if you're already compiling std yourself along with your program, then Rust doesn't need any special support to omit code that your program doesn't call.

That said, I could see something like this helping us if we want to hide old deprecated APIs and prevent using them from new editions.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 4:54pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/9 "2020-04-17T16:54:08Z")

</div>

> [@josh](#):
>
> That said, I could see something like this helping us if we want to hide old deprecated APIs and prevent using them from new editions

That's exactly the point

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 17, 2020, 5:03pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/10 "2020-04-17T17:03:04Z")

</div>

I'm not seeing how this would help any real-world use cases, unless it's subtly violating [the restrictions on edition changes](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md#negative-examples-what-edition-opt-ins-cant-do) that we need to keep all the editions mutually compatible.

In particular, I doubt we can use this for any trait implementations because that would affect coherence, and in general I _think_ it's ambigous what "the user" of an impl actually is when you consider non-trivial cases like [the classic "HashMap problem"](https://internals.rust-lang.org/t/looking-for-rfc-coauthors-on-named-impls/6275/2) with multiple crates and layers of generic code between `std` and the "user" (does anyone here grok trait/type systems well enough to confirm that?).

Plus, every new `std` API is already gated on whatever `rustc` version added it, just like editions are. Do we have any examples of `std` APIs (that aren't trait impls) that we'd rather gate on an edition than a `rustc` version? Or where it would matter at all?

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 6:16pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/11 "2020-04-17T18:16:22Z")

</div>

> [@Ixrec](#):
>
> coherence ... the classic "HashMap problem"

True, old `impl`-s stay and coherence still cannot be broken

> [@Ixrec](#):
>
> every new `std` API is already gated on whatever `rustc` version added it

- so currently using `std` API `X` is prohibited if `MSRV < X_startVersion`
- the suggestion is to also prohibit it if `edition > X_endEdition`

This is a tool to hide deprecated parts of API. It's indeed limited in power

---

<div class="post-metadata">

**Author:** ![chrisd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chrisd/32/7232_2.png) [@chrisd](https://internals.rust-lang.org/u/chrisd)\
**Post date:** [April 17, 2020, 6:40pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/12 "2020-04-17T18:40:23Z")

</div>

For a hypothetical example, take [`std::alloc::alloc`](https://doc.rust-lang.org/std/alloc/fn.alloc.html). The docs say:

> This function is expected to be deprecated in favor of the `alloc` method of the [`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html) type when it and the [`Alloc`](https://doc.rust-lang.org/std/alloc/trait.Alloc.html) trait become stable.

With edition gating, Rust circa 2030 could hide it from any code using the 2030 edition or newer, so that calling it is a hard error.

Perhaps more substantially there's [`std::mem::uninitialized`](https://doc.rust-lang.org/std/mem/fn.uninitialized.html) which "basically cannot be used correctly".

* * *

I don't know if this edition gating is a good idea or not but I think the reasoning is it can help keep the `std` from one day looking like a Rust history lesson (landmines included). Instead it would present a modern, clean interface to modern code.

Compatibility between editions will be preserved because it only pretends to remove deprecated interfaces. They would still be there. And old APIs would be internally re-written in terms of more modern ones where that's possible (this already happens, no?).

How this would be implemented in practice, I don't know.

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 17, 2020, 6:45pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/13 "2020-04-17T18:45:18Z")

</div>

Ah, okay, if it's _only_ for pseudo-removals then this makes sense to me. Since all of this only applies to `std`, it'd almost certainly be some kind of perma-unstable `#[rustc_hide_on_edition(2021)]` attribute so there's no need to design a "proper syntax" like the `pub(..2021)` suggested above (that's probably part of what threw me off).

The only real challenge there is what do we do with the docs pages. Can we make pseudo-removed APIs hidden _enough_ that we really get the cleanup benefits, without making them _so_ hidden that people start failing to locate docs for stuff they run across in existing code? I'm not sure.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [April 17, 2020, 6:58pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/14 "2020-04-17T18:58:46Z")

</div>

Why not add a `rust_2018` cargo feature to your crate which does this gating?

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [April 17, 2020, 7:14pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/15 "2020-04-17T19:14:37Z")

</div>

@ckaran @atagunov I'm familiar with the ongoing discussion of the 2021 edition. My point in asking "who would use this feature?" is that if the stdlib is the only user of this feature, then it doesn't need an RFC, syntax change, or new (publicly usable) attribute. The stdlib already uses internal-only macros. They could easily add another one that signals edition-related information.

The hard part isn't "what syntax should we use?" (because if stdlib is the only customer the answer is trivial: use a new custom attribute). The hard part is actually getting this to work at all because of the machinery involved.

To put it bluntly (with apologies), I'm not sure what the point of this discussion is if there aren't use cases for this feature outside of the stdlib.

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [April 17, 2020, 8:04pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/16 "2020-04-17T20:04:05Z")

</div>

If the only same use-case for this is the standard library, why does there have to be special syntax or some other construct? There could be something wholly confined to std, the details of which doesn't much matter.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 8:30pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/17 "2020-04-17T20:30:44Z")

</div>

> [@mjbshaw](#):
>
> The hard part is actually getting this to work at all because of the machinery involved.

Hi, the above is actually an attempt to sketch an implementation path:

- tweaks to visibility (as if it was a different kind of `pub`)
- std-aware `cargo` + conditional compilation (similar to how features work)

> [@mjbshaw](#):
>
> I'm not sure what the point of this discussion is if there aren't use cases for this feature outside of the stdlib.

This is a spin-off from [2021 edition](https://internals.rust-lang.org/t/2021-edition/12153/45) topic; one of the ideas discussed was if a hypothetical `202a` edition could not only remove deprecated syntax but also deprecated API-s. Sorry, should have been more clear about this; added an Update to the first post.

Indeed there is a lot less motivation to have this outside of std.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 17, 2020, 8:40pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/18 "2020-04-17T20:40:47Z")

</div>

> [@atagunov](#):
>
> std-aware `cargo`

Which is (unfortunately) a long ways off, definitely not within the "edition 202a" timeline.

Plus, "just use features" _doesn't work here_, because one std has to serve every edition simultaneously.

All the involved parties know _roughly_ how edition based visibility would look; add a `rustc_hidden_after_edition` attribute to `#[deprecated]` (or outside of it, w/e), and then have editions after that treat the deprecation as a hard error instead of a warning. That part isn't actually that hard.

The hard part is primarily the documentation story. How do you actually benefit from cleaning up the API surface without making functionality that is still there in older editions effectively undocumented? Most people will use the online rust-lang docs, not some local copy (which still isn't attached to a workspace anyway (which doesn't even have to use a singular edition)).

This is probably a solveáble problem, just not a solvéd one.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [April 17, 2020, 9:26pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/19 "2020-04-17T21:26:49Z")

</div>

> [@CAD97](#):
>
> The hard part is primarily the documentation story

Now _that_ looks easy 🙂 a doc page could consist of

- items visible in latest edition
- `<hr/>`
- title: `removed in edition 2021`
- "removed" items

Color/background/strikethrough/etc can be used to differentiate "removed" items from normal ones. There can possibly be a clickable button to switch the page into an "old edition" mode

> [@CAD97](#):
>
> "just use features" _doesn't work here_ , because one std has to serve every edition simultaneously

I guess the thinking was the set of necessary editions would be collected from all crates constituting project thus pulling in exactly the portion of `std` that's needed.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [April 17, 2020, 9:36pm UTC](https://internals.rust-lang.org/t/gating-api-on-editions/12178/20 "2020-04-17T21:36:30Z")

</div>

I have a different point which has to do with the idea of gating API on editions, something I thought of when recently reading about problems that could/would arise when adding implementations for `IntoIter` (as an iterator _by value_) to array-types.

This plays into the point that API-gating couldn’t really apply to trait impls as you can’t have a type implement a trait in one place but not implement the trait in another place, which is true.

The actual problem however was that calls of `x.into_iter()` for an `x: [SomeType; N]` currently auto-refs and call `into_iter()` on `&x` creating an iterator by-reference, so that adding the `impl` for the array can change the meaning of existing code. My idea here: Why not gate trait implementations on editions _just for the sake of method resolution_?

A method call expression would take into consideration at what edition the code it comes from is, and then it only takes impls that are in that edition into consideration. This would help avoid breaking existing code. It does what editions are for: you cannot actually _change_ the language or the std lib in a not backwards-compatible way, but you can change how new code is interpreted syntactically; making deprecated items “invisible” (i.e. hard errors) fits just as well into this category.

[Next page](https://internals.rust-lang.org/t/gating-api-on-editions/12178.md?page=2)
