# Pub(crate) keyword suggestion

**URL:** <https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367>\
**Category:** Uncategorized\
**Created:** [February 18, 2023, 2:10pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367 "2023-02-18T14:10:01Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [February 18, 2023, 2:10pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/1 "2023-02-18T14:10:01Z")

</div>

This is mostly a low-effort keyword name suggestion, but, as I didn't think of/notice it for the some amount of previous years, I decided to document it for posterity. Definitely not a "we should" suggestion, just "in theory we could". To cut to the chase:

**api** to me sounds like a nice keyword to capture "visible outised of the current crate" semantics:

```rust
/// Public API of the crate, guarded by semver, guarded by "unreachable_api"
api fn foo() { }

/// Not a part of the crate's API, but otherwise accessible throughout the crate
pub fn bar() { }

/// Private, visible only in the current module
fn baz() {}

// part of semver
api struct Widget {
  api name: String, // also part of semver
      id: u32, // clearly not semver
}

```

That is, in edition X we can introduce **api** keyword, which is synonym with today's **pub** , except that it also has `unreachable_api` as deny-by-default. In edition X+1, we re-purpose **pub** to mean **pub(crate)**.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [February 18, 2023, 2:23pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/2 "2023-02-18T14:23:36Z")

</div>

There used to be the `crate` keyword functioning the same as `pub(crate)`, but it was removed in [Remove feature: `crate` visibility modifier by jhpratt · Pull Request #97254 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/pull/97254) The following reason was given:

> Given the ambiguity observed with `struct X(crate ::ident)`, we don't think `crate` is going to happen. If someone wants to champion a new keyword or a new approach, they should start an MCP for that.

> <https://github.com/rust-lang/rust/issues/53120#issuecomment-1124065083>
>
> This is a sub-tracking issue for the RFC "Clarify and streamline paths and visib…ility" (rust-lang/rfcs#2126)
> dealing with the question of \`crate\` as a visibility modifier.
> 
> \- \[x\] Implement the RFC
> \- \[\] Adjust documentation (\[see instructions on forge\]\[doc-guide\])
> \- \[\] Stabilization PR (\[see instructions on forge\]\[stabilization-guide\])
> 
> \[stabilization-guide\]: https://forge.rust-lang.org/stabilization-guide.html
> \[doc-guide\]: https://forge.rust-lang.org/stabilization-guide.html#updating-documentation
> 
> \*\*Unresolved questions:\*\*
> 
> + \[\] How do we parse \`struct Foo(crate ::bar)\`?

---

<div class="post-metadata">

**Author:** ![Kray](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kray/32/6177_2.png) [@Kray](https://internals.rust-lang.org/u/Kray)\
**Post date:** [February 18, 2023, 7:11pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/3 "2023-02-18T19:11:44Z")

</div>

After thinking about it, I really like this keyword. It's logical even if a bit unusual. It's 3 letters just like `pub`. I think `pub(crate)` is annoying to write and causes _a lot_ of visual noise.

As a side note, if this was implemented, [public dependencies](https://rust-lang.github.io/rfcs/1977-public-private-dependencies.html) should also be called "api dependencies" instead.

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [February 18, 2023, 7:48pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/4 "2023-02-18T19:48:17Z")

</div>

Rather than make `api` a new keyword, why not just require `pub(api)` instead?

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [February 18, 2023, 8:11pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/5 "2023-02-18T20:11:38Z")

</div>

`api` is a very common identifier. Reserving it as a non-contextual keyword would be highly disruptive to the ecosystem. Having it be contextual and only breaking `struct X(api ::ident);` still seems likely to be an issue, in crates that have a top-level `mod api;` (I'm not sure if this is the only situation that would be impacted by a contextual visibility keyword, just that it is one that would be).

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [February 18, 2023, 9:36pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/6 "2023-02-18T21:36:27Z")

</div>

`pub(whatever)` is still more cumbersome to type and visually noisier than a simple standalone keyword.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 18, 2023, 9:43pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/7 "2023-02-18T21:43:33Z")

</div>

But `api` can still be a context keyword if it's followed by an identifier or other keyword, like `api fn` versus `api.x += 1;`. `api fn` isn't a valid expression.

My language and TypeScript do this very commonly. For example, there `type` is a context keyword.

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [February 18, 2023, 10:03pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/8 "2023-02-18T22:03:45Z")

</div>

Personally, I consider adding resistance to making something api-public a good thing. For libraries, making something api-public should be a deliberate decision. And this doesn't change anything for binaries, which can still just use `pub` for everything.

Also, `api` just doesn't stand out to me as a visibility modifier.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 18, 2023, 10:09pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/9 "2023-02-18T22:09:41Z")

</div>

I agree lexical `api` doesn't fit at all, but to me this idea reminds me of ActionScript 3 annotatable definitions (where an arbitrary identifier can be used as access modifier).

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [February 18, 2023, 11:12pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/10 "2023-02-18T23:12:47Z")

</div>

As my comment went on to say that still causes ambiguity in (at least) the same position as having `crate` be a keyword with two different contextual meanings does.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [February 19, 2023, 9:01pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/11 "2023-02-19T21:01:44Z")

</div>

> [@pitaj](#):
>
> consider adding resistance to making something api-public a good thing. For libraries, making something api-public should be a deliberate decision.

I don't think it needs to be burdensome to force people to think about their public API. In the Rust ecosystem it's already well-known what kind of committent this is.

OTOH `api` being locally explicit makes it clearer what actually is part of the public API, as opposed to `pub` that may or may not be the public API, depending on on accessibility of parent modules and re-exports.

So I think `api` helps people think "do I really want this to be in the crates API?" as opposed to mistakes like "I'll write `pub`, because `pub(crate)` two shift presses too many, and hope this type isn't exported".

> [@pitaj](#):
>
> `api` just doesn't stand out to me as a visibility modifier.

This is because the keyword is without a precedent in Rust or other languages, but inherently it's not any different from other 3-letter acronyms, and I think it will stand out enough once people get used to it, and editors highlight it as a keyword.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 19, 2023, 9:26pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/12 "2023-02-19T21:26:13Z")

</div>

And it doesn't need to be a strictly reserved word. For example, will it break compatibility if Rust introduces `api` as a context keyword followed by an identifier or another keyword? I guess not, because to start with, `api blahblah` isn't valid anywhere in Rust. In F# for example `api blahblah` is something, so F# can't do this (it's a call expression).

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [February 19, 2023, 9:28pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/13 "2023-02-19T21:28:04Z")

</div>

> [@hydroper1](#):
>
> `api blahblah` isn't valid anywhere in Rust

but `api ::blahblah` is -- it's the same problem as `crate`.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 19, 2023, 9:28pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/14 "2023-02-19T21:28:31Z")

</div>

I said identifier "lexically", not a identifier expression (including punctuator tokens).

`api ::blahblah` consists of 3 tokens:

- `api`
- `::` (punctuator)
- `blahblah`

`api blahblah` consists of 2 tokens:

- `api`
- `blahblah`

And like I said, TypeScript does the same for the `type` context keyword. My language too, including for `enum`.

So no need for a new "Rust edition" for something that can be a context keyword.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 19, 2023, 9:40pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/15 "2023-02-19T21:40:14Z")

</div>

I don't see how that's supposed to prevent the issue of `struct X(api ::ident)`. This is a context where a visibility is expected, so `api` being a context keyword doesn't prevent the ambiguity. Also note that both `api::ident` and `::ident` are valid paths, so that can't be used to disambiguate.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 19, 2023, 9:43pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/16 "2023-02-19T21:43:35Z")

</div>

I think you don't understand how parsing works. It's a bit tricky to explain, and you seem to think that `::` is part of the identifier. Anyway, context keywords just work in this case.

Here's my parser: [violetc/Parser.cs at master · violetscript/violetc · GitHub](https://github.com/violetscript/violetc/blob/master/VioletScript.Parser/src/parser/Parser.cs)

Somewhere you'll see that I've a method to determine if a statement or directive starts with a set of strict reserved words or context keywords and more and more. It's a bit tricky though.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [February 19, 2023, 9:50pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/17 "2023-02-19T21:50:31Z")

</div>

It doesn't matter whether `::` is part of the identifier or not, today you can write `struct X(pub ::foo::Bar);`. If `api` is to replace `pub` then it must be possible to change this to `struct X(api ::foo::Bar);`. Which means that if `api` is a contextual keyword it must be a keyword in more situations than just `"api" IDENT` (some of which other situations are ambiguous).

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 19, 2023, 9:52pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/18 "2023-02-19T21:52:40Z")

</div>

Are you saying `pub` is usable out of just, for example, `"pub" fn IDENT`? Like `pub::x` is a valid expression? I didn't know. So you're saying this proposal implies that `api` must be usable just like `pub` as in `api::x`?

I'll try it in the playground yet.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [February 19, 2023, 9:54pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/19 "2023-02-19T21:54:17Z")

</div>

Yes, inside `struct X(pub ::foo::Bar)` there is a valid [`TupleField` expression](https://doc.rust-lang.org/nightly/reference/items/structs.html#structs) `pub::foo::Bar`.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [February 19, 2023, 9:58pm UTC](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367/20 "2023-02-19T21:58:41Z")

</div>

I see, but is that syntax really needed? The proposal didn't mention anywhere of using `api` as a prefix qualifier with `::`. Like, I think `::x` is more useful than `api::x`.

`::x` will similiarly resolve to a crate.

IMO it'd only be useful if you could do something like `self.api::some_field`, which doesn't exist in Rust currently with `pub`.

[Next page](https://internals.rust-lang.org/t/pub-crate-keyword-suggestion/18367.md?page=2)
