Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Modules) Tracking issue for `crate` as a visibility modifier #53120

Open
Centril opened this Issue Aug 6, 2018 · 59 comments

Comments

Projects
None yet
@Centril
Copy link
Contributor

Centril commented Aug 6, 2018

This is a sub-tracking issue for the RFC "Clarify and streamline paths and visibility" (rust-lang/rfcs#2126)
dealing with the question of crate as a visibility modifier.

Unresolved questions:

  • How do we parse struct Foo(crate ::bar)?
@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Aug 6, 2018

Comments about crate as a visibility modifier:

Parsing ambiguity

Unnatural / Confusion / Not improvement

A good idea

pub(extern) instead

Bikeshed

An early preview

Dedicated thread

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Aug 6, 2018

Personally, I am very much in favor of crate as a visibility modifier and I share @stepancheg's comment here. I think that we should encourage smaller and stricter visibilities and crate does just that.

@lilianmoraru

This comment has been minimized.

Copy link

lilianmoraru commented Aug 6, 2018

I'm personally ok with writing pub(crate), the intent seems very explicit.
The example given by @johnthagen is really painful to see(using crate):

use crate::menu::{Sound, Volume};

crate mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

crate mod color; especially seems confusing, you definitely need to put a bit of thought on what's happening there.

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Aug 6, 2018

Some of these examples are very C-static-esque- intuitively related but really surprisingly distinct.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Aug 6, 2018

The example due to @johnthagen does not read poorly to me. In fact, it reads naturally and I quite like the symmetry. It is beautiful in a way.

If the readability of:

crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

becomes a problem; then an IDE/editor that understands the syntax of Rust can highlight the crate tokens in the different positions with different colors. That should clear up the difference well I think.

@matklad

This comment has been minimized.

Copy link
Member

matklad commented Aug 6, 2018

crate as visibility modifier is definitely weird: it uses very rust-specific keyword for a thing which is not specific to rust. Kotlin & C# use internal for this.

I'd personally would want to reuse pub for crate-visible, and go for a more screamy syntax for world visible, like pub* or pub!.

@johnthagen

This comment has been minimized.

Copy link
Contributor

johnthagen commented Aug 6, 2018

It's been brought up before, but I think the root issues I see are:

  1. crate is a noun. I think pub(crate) is long and odd looking, so I fully support replacing it with something, but it did have the public adjective associated with it, so grammatically it flowed better.
  2. crate is now used as the anchor for "this-crate" imports, which means something different than "wherever this is defined, it's also exported visibly from this crate"
// Here `crate` means the root of this crate.
use crate::menu::{Sound, Volume};

// Here, `crate` means: export crate::game::color
// The `crate` is referring to `color`, not the root.
crate mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
// Same potential confusion as `crate mod color`
crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

Compared to an example, using @matklad's internal from Kotlin/C#.

use crate::menu::{Sound, Volume};

internal mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
internal struct ColoredText {
    internal color: types::Color,
    internal text: &'static str,
}

I'm not saying internal is the right keyword (Rust likes it's very short abbreviations, and int is unfortunately full of C/C++/Java confusion), but I personally think that the second example is immediately more readable.

I also think the crate visibility keyword will be confusing to people coming to Rust from other languages. If even many of us involved enough in Rust to comment on these threads are jarred, I'd have to imagine it will trip up people new to Rust as well.

@seanmonstar

This comment has been minimized.

Copy link
Contributor

seanmonstar commented Aug 6, 2018

The slightly longer syntax of pub(crate) may not be such a big deal if weren't becoming a warning/error to have pub items that aren't reachable outside the crate. I personally wish that if I had a pub(crate) struct Foo { ... }, that the compiler could realize that all the pub fns in a impl Foo are clearly not reachable, and not bother me about it.

I find it to be just busy work currently in Rust 2015 if I ever mark a type from pub struct Foo to pub(crate) struct Foo, how the compiler then yells in all the places that some other pub fns exist using the suddenly pub(crate) type, when the problem isn't real, because the other type is also pub(crate).

@johnthagen

This comment has been minimized.

Copy link
Contributor

johnthagen commented Aug 6, 2018

I also find @matklad's idea of re-purposing pub as crate-public and using export or something for world-visible exports. But that may be too big a divergence for an edition?

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Aug 7, 2018

Repurposing pub as crate-public and adding a new visibility for world-public was the proposal before the current version. Such a change to existing semantics was considered too drastic even for an edition, which is why pub is now keeping its current meaning.

What was less discussed and considered, I think, was repurposing pub solely via a lint. Perhaps we could switch the lint from "warn on pub that's not accessible outside the crate" to "warn on pub that is accessible outside the crate," and add a purely optional pub(extern)/export keyword. That is, don't change any semantics, just add a lint-silencing syntax.

I suspect this would be less disruptive, based on the assumption that there are fewer world-public items than crate-public items. It would also preserve the intuitive (though subtly incorrect) meaning of pub as "export from the current module" rather than confronting everyone with visibility's true behavior.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Aug 7, 2018

Rust likes it's very short abbreviations, and int is unfortunately full of C/C++/Java confusion

FWIW, though it only saves two characters, if we wanted to abbreviate internal, the "right" abbreviation would probably, by analogy with external, be intern. Unfortunate that that is also a noun with a commonly understood, different meaning. Oh well.

@johnthagen

This comment has been minimized.

Copy link
Contributor

johnthagen commented Aug 7, 2018

@glaebhoerl intern is a good option to consider! ❤️

The symmetry with extern is really nice, and IMO would greatly reduce the potential confusion with the noun form of intern.

It's short, (only 1 more character than crate) and doesn't clash with use crate::.

The updated example would look like:

use crate::menu::{Sound, Volume};

intern mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
intern struct ColoredText {
    intern color: types::Color,
    intern text: &'static str,
}
@CasualX

This comment has been minimized.

Copy link

CasualX commented Aug 9, 2018

I've mentioned it before, but I'm not sure what the problem is with nouns used as adjectives?

To recap: there are plenty of nouns that can be used as adjectives, eg. a house cat, a computer mouse, a computer desk, etc... A google search for english nouns used as adjectives seems to indicate there's nothing inherently wrong although not all nouns work as adjectives.

Let's try it:

crate mod hello; A crate module named hello, feels fine.
crate fn world() {} A crate function named world, feels fine.
crate struct Foo; A crate struct named Foo, feels fine.
crate enum Bar {} A crate enum named Bar, feels fine.
crate trait Baz {} A crate trait named Baz, feels fine.

crate use self::local::Foo; Ack, this one does not work, a crate use? You can read it as crate usable item named Foo. It does break the pattern.

It can also be awkward when used in front of struct members and even more in combination with crate as the root of a path.

While crate isn't perfect, I'm not convinced that 'being a noun' is a deciding factor.

@UtherII

This comment has been minimized.

Copy link

UtherII commented Aug 10, 2018

The problem is that it is very uncommon. There is no programming language I know that use nouns as type modifier.

@epage

This comment has been minimized.

Copy link

epage commented Aug 15, 2018

@Centril

becomes a problem; then an IDE/editor that understands the syntax of Rust can highlight the crate tokens in the different positions with different colors. That should clear up the difference well I think.

Personally, while I find features of different editors nice, I don't think we should design the language with the assumption of a sufficiently advanced editor. I felt like C# was designed this way and it was a major factor in my frustration with that language.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Aug 15, 2018

@epage I think crate as a visibility modifier is a good idea regardless of highlighting; I'm merely suggesting that highlighting is additional mitigation. In particular, it should be fairly trivial for any editor to highlight crate:: differently than crate field because the former is always crate + :: which is easy to check for in all cases except crate ::foo::bar (but this will be fairly rare..).

@matklad

This comment has been minimized.

Copy link
Member

matklad commented Aug 16, 2018

As an IDE person, I think such highlighting would add significant amount of noise for a very little amount of information, netting negative. IMO (this is highly personal, but informed by both using and implementing powerful IDEs) highlighting works best when it conveys semantic non-local information (does this usage refers to a variable that was declared with mut) and de emphasizes local "boilerplaty" aspects of code (so all keywords should be styled exactly the same).

@zesterer

This comment has been minimized.

Copy link
Contributor

zesterer commented Aug 16, 2018

It seems to me that dom (i.e: domestic) is a potential candidate.

It has three letters (nice for alignment, easy to remember), it's not a noun, and - other than 'Document Object Model' - I don't think it has any particular ambiguity attached to it.

pub struct MyStruct {
    dom num: i32,
    pub msg: String,
}

Does anybody have thoughts on this?

@epage

This comment has been minimized.

Copy link

epage commented Aug 16, 2018

One angle on this that I've seen mentioned but couldn't find in the summary (thanks for doing that btw!) is how a shortcut fits in with the existing pub() syntax.

If pub and <something> (e.g. crate) have special meaning, it further reduces the visibility, and by extension familiarity, of pub(<something>). Whatever solution we go with, I think it should support or replace the existing machinery rather than being yet another one.

For example, if we use crate or replacement:

  • Should crate be extended to take on scoping restrictions (e.g. crate(<something>))?
  • Should we deprecate pub() so pub only has one meaning?

Considering this and my understanding of the goal (clarify public API from internal API), led me to recreate @vitiral's idea of pub(extern).

  • Fits within existing machinery
  • imo improves the existing machinery by making pub a shortcut of pub(<something>) rather than being a special case
  • If the public API is significantly smaller than the private API, then we've weighted the syntax the right way.
  • But might confuse people coming from other languages where public means it might be in your public API.
@epage

This comment has been minimized.

Copy link

epage commented Aug 16, 2018

RE Impact on encapsulation

One benefit of the existing pub system is encapsulation. The easy-path is to expose API only one-level up. This makes it easier to have things public to parts of a crate but private to the whole create.

While there will still be pub(super), having a shortcut for pub(crate) will push people in the direction of using it more, encouraging people to not encapsulate their APIs.

I suspect this isn't an issue because of the culture of small crates.

But in considering this, it gives me another iteration on my above comment on pub(extern)

  • pub should be a shortcut for pub(super)
  • pub(extern) is required for your public API.

I previously brought up the concern of people transitioning from other languages. This better aligns with them.

  • More closely matches how public works in various languages
  • Some languages tend to have a distinct mechanism for public API, so this is explainable to them.

imo this is the best of all worlds. So tear it apart and help me understand why not :)

@parasyte

This comment has been minimized.

Copy link

parasyte commented Aug 16, 2018

I still hate the pub(foo) syntax. Hyperbolically, it looks like it can't decide if it's a function call or a mashup of multiple keywords. We don't use let(mut) or for(in) so what's the deal with this one?

@vitiral

This comment has been minimized.

Copy link
Contributor

vitiral commented Aug 16, 2018

@parasyte pub<foo> for the win! After all, isn't it a type of visibility?

@lu-zero

This comment has been minimized.

Copy link
Contributor

lu-zero commented Aug 16, 2018

pub<crate> or pub(crate) feel better indeed.

@ralfbiedert

This comment has been minimized.

Copy link
Contributor

ralfbiedert commented Aug 16, 2018

Some thoughts from someone who changed camp:

At first I was very opposed to crate and thought "this is ruining the nice pub".

I then tried it side-by-side in some of my projects and let it sink in.

Frankly, after a few days I couldn't stand looking at pub(X) anymore, it feels clunky in comparison, and harder to read.

Initially I feared there might be (visual) ambiguity; but to me the opposite happened: If I see crate now I know it's, well, "crate stuff". Whether that is importing modules or declaring visibility. What exactly is in the overwhelming majority of cases very clear from the context (sort of like ambiguity in English).

I can see there might be still be residual "harder" (visual) ambiguity in some cases, but I wouldn't want to trade that back for what now feels like an massive quantitative readability win (as in: "source code lines that require less visual tokenization / effort vs. source code lines that became more ambiguous" ).

From that angle crate - intern (or any other asymmetry) would also feel like a step back.

Having said this, I don't know about parsing ambiguity. If I had to pick one, I'd much rather have a good story around "crate means crate stuff" than a good story around "crate ::foo::bar just works".

@superseed

This comment has been minimized.

Copy link

superseed commented Aug 21, 2018

@rpjohnst Is it really what it always meant? Wasn't it the chain of "visible from super" from the top of the crate which made an element exported, and not qualifying the leaf element itself as pub?

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Aug 21, 2018

No, that's not the whole story, and @seanmonstar's clarification hints at the rest. The biggest exception is reexports- you can pub use something whose parent modules are private. A weirder example is something like this, where you're allowed to use a pub item in a public interface even if its parent modules are private.

And going in the other direction, pub(crate) and lesser visibilities can't be bypassed in the same way- you can't pub use something that's not already pub, even if the pub use is not itself visible from outside the crate.

So an item's own visibility is not directly about its visibility to super, but its "upper limit" of visibility anywhere.

@superseed

This comment has been minimized.

Copy link

superseed commented Aug 21, 2018

Oooh okay, thanks for the clarification! I had a much more naive model in mind. It makes more sense regarding previous comments about "the current meaning of pub".

@LukasKalbertodt LukasKalbertodt referenced this issue Aug 23, 2018

Closed

Compile on stable Rust 2018 #13

7 of 7 tasks complete

@Centril Centril added I-nominated and removed I-nominated labels Aug 23, 2018

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 23, 2018

We discussed briefly today in @rust-lang/lang meeting:

  • Many of us feel positive about this but there are lingering doubts about the choice of keyword, and whether it can create confusion when combined with crate::foo::bar paths
  • However, it's worth pointing out that we do have to decide what sort of way to resolve struct Foo ( crate :: foo :: Bar ) -- is this a private field of type (crate::foo::Bar) or is it a crate field of type ::foo::Bar?
    • I'm honestly not sure what we parse it is as today
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 23, 2018

Answer: we parse it as a path (playground).

This seems.. probably ok to me, because I think that ::foo::bar paths will become increasingly rare.

@epage

This comment has been minimized.

Copy link

epage commented Aug 23, 2018

Many of us feel positive about this but there are lingering doubts about the choice of keyword, and whether it can create confusion when combined with crate::foo::bar paths

@nikomatsakis are there meeting notes or a summary for us to catch up on? Within this thread, I've not seen discussed at least one of my concerns[0] nor much discussion on the counter proposals. Maybe [0] and some of the others were discussed in the various internals threads but that is a lot to dig through.

[0] creating a parallel visibility syntax pushing pub(...) into obscurity with a feeling we should either remove or embrace pub(...)

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Aug 23, 2018

@epage

@nikomatsakis are there meeting notes or a summary for us to catch up on?

No sorry; We did not discuss it for very long (a few minutes at most) and did not write down any meeting notes about it.

@eddyb briefly alluded to my as a shorter and more ergonomic visibility modifier.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Aug 24, 2018

I think I said mine but my is even shorter, lovely!
(For the record, I was half-joking in the meeting)

EDIT: if my is crate-local, can we replace pub with our? e.g.:

our struct Foo(my FooImpl);
@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Aug 24, 2018

(For the record, I was half-joking in the meeting)
if my is crate-local, can we replace pub with our?

Perl: making jokes a reality.
https://perldoc.perl.org/functions/my.html
https://perldoc.perl.org/functions/our.html

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Aug 24, 2018

my is nice (and has come up before), the thing is that it's not any clearer than local, internal, or whatever, with respect to to what (or in its case, whose), which is the whole problem.

The awkward situation we're in is that we want to have three privacy levels -- "completely public", "completely private", and "somewhere in between" (i.e., crate-level) -- and due to backwards compatibility constraints we're stuck with the first of these necessarily being pub, the second being the implicit default, and having to come up with something new for the third. And English does not have many words which denote "neither completely global, nor completely local, but somewhere in between" with precision.

And the crate keyword is the one which does satisfy this, because it says right in the name what the actual scope is -- it's the crate. But (before you break out the "I knew it!"s), the price of this is that it's no longer evident that it's a visibility modifier. "Pub" is short for "public", that, one can intuit. But no other language has the concept of a "crate" (with that name); to have any hope of making sense of crate struct, one has to first learn about this.1 It requires us to make a further withdrawal from the "language strangeness budget", and opinions may differ about whether the balance is still positive.

Meanwhile pub(crate) solves both problems -- it tells you that it's a visibility modifier, and it tells you what the scope is -- but in exchange it's long and awkward.

So that's basically the shape of the predicament.

1 (Someone above described an interaction which went, "they asked what crate meant, I told them it's a visibility modifier, and that was the end of it". The problematic, and possibly more common, situation is when you don't happen to have a Rustacean sitting next to you.)

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Aug 24, 2018

FWIW, I'd be totally okay with our or my for crate-local items.
our is even a three-letter keyword and aligns nicely with pub and with Perl.
Is the problem that they sound too informal (for native English speakers?)?

@johnthagen

This comment has been minimized.

Copy link
Contributor

johnthagen commented Aug 24, 2018

How do people feel about intern? It's one character longer than crate, but other than that I think it will be more intuitive than crate to people new to Rust and has some nice symmetry to theextern keyword.

@letheed

This comment has been minimized.

Copy link
Contributor

letheed commented Aug 24, 2018

IMO our and my have the same weakness as local and internal: they're not very clear about their scope. local in particular is quite confusing, since the scope would be radically different from local variables where local means private to the enclosing scope, which for an item would be the module, not the crate. I find internal a bit unspecific. Internal to what? The module? The type? The crate? It may be obvious for those who come from languages where it is used but it won't necessarily be for others. our and my are even more vague. In contrast crate is very clear about the scope.

Regarding pub(extern), I actually have a question. Does it make any sense to ever have extern "C" fn foo() {}, without the pub in front? Because if not, we could reuse extern fn foo() {} for our regular, non "C" abi Rust functions as well. I was thinking that we could unify that and not keep the extern syntax special for FFIs. That would mean extern now desugars to pub(extern), pub stays the same as today but accepts an optional ABI string when the item supports it, and a lint for pub items being exported without pub(extern) or extern.

extern fn foo() {
    println!("Just called a Rust function from Rust!");
}

#[no_mangle]
extern "C" fn foo_from_c() {
    println!("Just called a Rust function from C!");
}

I haven't seen that mentioned in the threads I've read so apologies if this has been discussed before!

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Aug 24, 2018

Does it make any sense to ever have extern "C" fn foo() {}, without the pub in front?

Yes- sometimes you only want to use foo as a function pointer, for example. And in fact the syntax extern fn foo() {} can't be reused for this anyway because extern without "C" defaults to the C ABI, and this is considered idiomatic at least by some.

@stjepang

This comment has been minimized.

Copy link
Contributor

stjepang commented Aug 24, 2018

Here's a suggestion that came up long time ago - maybe we can give it another chance now that some aspects of the new module system have been crystallized?

// Public to the world.
pub struct Foo;

// Private to the crate.
priv struct Foo;

// Basically not visible at all (only inside the module).
struct Foo;

I believe this makes sense if one thinks of:

  • "public" as "public to the world"
  • "private" as "private to the crate"
  • "no visibility modifier" as "basically not visible at all"

Some people had a knee-jerk reaction to priv not being the most restrictive one, but I want to make two points about that:

  1. In Rust, modules are used to organize things under namespaces, while crates are used to define interfaces. So if a crate is a "unit of API", then it makes sense for visibility modifiers to talk about crates primarily.

  2. I think Java made a mistake of private meaning "private to the class" and no visibility modifier meaning "visible inside the package". To me, it makes more sense for no modifier (i.e. the default) to be the most restrictive.

@stevensonmt

This comment has been minimized.

Copy link

stevensonmt commented Aug 24, 2018

@stjepang I would argue that in most other circumstances "private" is going to have a more restrictive connotation than an unmodified state. The private-default-public spectrum in a general sense is analogous to protected-available-advertised.

A private club is more exclusive than a club.
A private act implies that some effort was taken to hide from general view.
A private thought should be a redundant concept given the failure of evolution to endow us with telepathy, but most people recognize it to mean a thought intended not to be shared.

As an inexperienced language learner, I would also suggest that an additional keyword is less of a cognitive burden than a single keyword with multiple context-dependent meanings. See Costello, L and Abbot, B "Who's on first", 1938.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Aug 24, 2018

I feel that my and our would have connotations we don't want, leaving aside the difficulty of reserving these as keywords. They make for an amusing joke, but I don't think we should go that route.

I honestly feel like people would learn what crate visibility means. I think the bigger problem comes from code that becomes difficult to read or ambiguous to parse:

crate struct S(crate crate::Foo);

crate struct S(crate ::Foo);

I personally don't see those as showstoppers, but they're definitely legitimate concerns here.

@seanmonstar

This comment has been minimized.

Copy link
Contributor

seanmonstar commented Aug 24, 2018

There's a parallel of pub(path) in the Scala language, which is private[path], which acts pretty much the same. It reads slightly differently, saying "this item is private, only allowing people within $path to view it". But making something private in Scala requires an annotation, as the default is public, which isn't the case in Rust.

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Aug 24, 2018

It occurs to me that the C++ concept of friends is also similar to pub(path), as another point of precedent.

@aturon aturon removed this from the Rust 2018 RC milestone Sep 5, 2018

@gdouezangrard

This comment has been minimized.

Copy link

gdouezangrard commented Sep 9, 2018

Ultimately, the issues are:

  1. the crate keyword is used for both relative paths imports and as a visibility modifier,
  2. the crate keyword prevents a unified visibility modifier syntax like pub(...),
  3. some dislike the pub(crate) syntax (too long, looks like a function call).

After 5 minutes of really deep thinking, I came up with the following... :P

Special Syntax for the Visibility Modifiers

(using @ as an example)

@pub use crate::Foo;

@crate struct Bar;

I personally find that quite ugly and I would not want to type either @crate or pub(crate).

Distinct Visibility Modifiers Keywords

Since there's already the bare pub and extern, I think the crate keyword fits in quite well (unsurprising when coming from languages with the usual public, protected, private keywords).

crate struct Foo;

crate fn path() -> PathBuf { ... }

But as I said, that doesn't work well with the crate import prefix and I'm starting to feel like we got this backwards. I feel the real issue lies with the path clarity changes, for instance, with no syntax highlighting:

use crate::utils;

looks like crate hasn't any special meaning.

With great inspiration from the declarative macros syntax, instead of finding some kind of unified syntax for visibility modifiers, I would rather have the following:

use std::io;
use std::path::Path;

use log::info;

use $crate::utils;

crate fn hello() -> io::Result<()> {
    utils::rm_rf(Path::new("/"))?;
    info!("Goodbye, World!");
}

(self, super and crate special anchors for paths imports would need a prefix, for instance, $crate, which makes it quite clear they are special and look like variables)

Convoluted example:

crate struct Foo(crate crate::Bar);

becomes:

crate struct Foo(crate $crate::Bar);
@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Sep 15, 2018

It appears there's a duplicate tracking issue: #45388.
Closing that one in favor of this one.

@ehuss ehuss referenced this issue Oct 14, 2018

Open

Path and module changes (RFC 2126) #291

3 of 6 tasks complete

Centril added a commit to Centril/rust that referenced this issue Jan 26, 2019

Rollup merge of rust-lang#57913 - h-michael:fix-crate-visibility-modi…
…fier-issue-number, r=Centril

Change crate-visibility-modifier issue number in The Unstable Book

rust-lang#45388 is closed.
Because, it's duplicate issue of rust-lang#53120.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.