Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upItem-level blocks (was: Item-level *scopes*) #2377
Conversation
This comment has been minimized.
This comment has been minimized.
|
I think this is either a subset of #2128 or a small extension to it. Not quite sure which. |
This comment has been minimized.
This comment has been minimized.
|
I like this idea, if scoped modules have an actual scope, and that the items within have the visibility they provide, excluding 100% private items (i.e. anything not I think that item scope should be elaborated outside of attributes, because imho a solution which works exactly like Simple use case:
Scopes are useful here because the
while shadowing works if it's in a more specific scope, if those two things have the same scope, it'll error. |
Centril
added
the
T-lang
label
Mar 30, 2018
This comment has been minimized.
This comment has been minimized.
Nemo157
reviewed
Apr 3, 2018
|
Despite my individual comments, I think actual item-level scopes would be super useful in #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
extern crate serde as _serde;
#impl_block
};This seems to be a very different use of the word "scope" than what this RFC proposes though. |
| use c; | ||
| use d; | ||
| } | ||
| ``` |
This comment has been minimized.
This comment has been minimized.
Nemo157
Apr 3, 2018
Contributor
This example suggests that there won't be any actual scoping happening, it appears to be expecting the "scoped" use statements will be exported to the parent scope.
For example, would this compile or be an error:
{
use a;
}
fn foo() {
a::foo();
}If it is actually introducing scopes then I think an actual use of the uses should be added to the examples to make them more like real code.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
Actually wait. I think the idea is that things inside the {} are visible at the top-level.
So this should be possible:
#[cfg(target_os = "linux")] {
use a, b, c, d;
}
...
#[cfg(target_os = "linux")]
fn do_linux_things() {
a::blah();
}
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
But I do see that there is an inconsistency. In regular Rust code, uses are scoped. So this doesn't work:
fn f () {
let _ = Path::new("lalala");
}
fn main() {
use std::path::Path;
f();
}
This comment has been minimized.
This comment has been minimized.
Nemo157
Apr 11, 2018
Contributor
Yep, I think the new example on the other thread clarifies that this should be auto-exported to the parent scope. I wonder if there's some alternative phrasing for this that will reduce confusion on whether the items defined in the "item-level scope" are scoped to that block or available in the parent scope.
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
The only other idea I have (which is less pretty) is:
#[cfg(...)]
parent! {
...
}
Where the purpose of parent! is to make it explicit that the new scope is "injected" into the parent scope. But then that raises questions about whether such an interface is general:
fn f() {
{
parent! {
let x = 1;
}
println!("{}", x);
}
}
Should work?!
I don't see any need for such a use-case, so I'd favour not going down that path, but instead documenting that item-level scopes re-export to the top-level (module) scope. Full stop.
This comment has been minimized.
This comment has been minimized.
Nemo157
Apr 11, 2018
•
Contributor
By phrasing I was mostly referring to the documentation/naming of the feature. Mostly about removing the word "scope" from the name since visibility and scope are very tightly coupled terms. One alternative would be to focus on "block" instead, maybe "conditional item blocks"? Blocks are associated with visibility, but less so than scope.
| } | ||
| ``` | ||
|
|
||
| Which seems overly verbose and complicated. |
This comment has been minimized.
This comment has been minimized.
Nemo157
Apr 3, 2018
Contributor
A better example of a currently usable alternative is:
#[cfg(debug_assertions)]
use ::{a, b, c, d};which I think is definitely good enough for this specific use case.
This comment has been minimized.
This comment has been minimized.
Ixrec
Apr 3, 2018
Contributor
Strongly agreed, this is what I was trying to say with my previous comment linking to #2128. If the only motivation for "item-level scopes" is to apply an attribute to several uses, then your syntax as enabled by that RFC is the better solution.
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
It depends if people would like to (for example), batch a load of function defs and/or data structures into a guarded scope. Do you think that might be useful? If not, then perhaps this RFC is superfluous?
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
I can imagine one such scenario: for platform abstractions, where each platform might have it's own data structures and functions.
#[cfg(target_platform = "linux")] {
use something::only::linux::uses;
use more::linux::stuff;
const SOME_SPECIFIC_PATH: &'static str = "/sys/blah/flibble/linux_specific123";
struct LinuxThingy1 {
...
}
impl LinuxThingy1 {
...
}
struct LinuxThingy2 {
...
}
impl LinuxThingy2 {
...
}
}
#[cfg(target_platform = "windows")] {
... lots of completely different imports and data structures...
}
#[cfg(target_platform = "freebsd")] {
... lots of yet different imports and data structures...
}
This comment has been minimized.
This comment has been minimized.
Nemo157
Apr 11, 2018
Contributor
That's a much better example, another relevant example could be replacing the if_std! macro used in futures.
This comment has been minimized.
This comment has been minimized.
vext01
Apr 11, 2018
Author
Yes, that would help there too.
But I'm a little spooked now, because as you said above, I didn't intend to introduce a "real scope" but users may expect one because of the "{ ... }".
This comment has been minimized.
This comment has been minimized.
This is something that is supposed to be done through macro hygiene and not module-level blocks. |
This comment has been minimized.
This comment has been minimized.
fknorr
commented
Apr 6, 2018
|
Regarding the syntax, it might be a good idea to sell item-level scopes as "anonymous modules": #[cfg(debug_assertions)]
mod {
// ...
}This clarifies it as an item-level scope and allows easier visual recognition of the block start, since It also has precedent with C++'s concept of anonymous namespaces, where |
This comment has been minimized.
This comment has been minimized.
|
@fknorr I'm not sure about spinning it as an anonymous module. The items inside a item-level scope should be visible at the top-level of the module, whereas a sub-module would have its own name-space. So your suggestion implies that we special case item-level scopes? |
This comment has been minimized.
This comment has been minimized.
Welcome and thank you for contributing to the design of Rust! With respect to process, various people will comment, etc. Currently, the language team is primarily focused on urgent RFCs that need to be settled before the new edition. Eventually however, the language team will discuss this RFC in a meeting and they will ask for changes or someone in the team will propose to merge / postpone / close the RFC. |
Centril
reviewed
Apr 12, 2018
| # Guide-level explanation | ||
| [guide-level-explanation]: #guide-level-explanation | ||
|
|
||
| An Item-level scope is allowed wherever an Item may appear. Item-level scopes |
This comment has been minimized.
This comment has been minimized.
Centril
Apr 12, 2018
Contributor
I believe as currently framed, this RFC constitutes a breaking change.
Consider for example the following snippet which is valid today:
fn main () {
#[cfg(debug_assertions)] {
struct X;
}
#[cfg(debug_assertions)] {
struct X;
}
}Here, the struct Xs are items, but my understanding of this RFC is that struct X would both be exported to the parent scope (fn main() { .. }) and thus cause a conflict for existing code which the compiler doesn't know how to resolve.
The mod { .. } idea does not have this problem tho.
This comment has been minimized.
This comment has been minimized.
vext01
Apr 17, 2018
Author
The blocks that I'm proposing appear only at the top level of a module. The semantics of your above example should be untouched.
This comment has been minimized.
This comment has been minimized.
Centril
Apr 19, 2018
Contributor
That's true; However, it may cause confusion between the semantics of top level items and items inside functions. Meanwhile, mod { .. } as anonymous modules do not cause such confusion.
This comment has been minimized.
This comment has been minimized.
fknorr
commented
Apr 14, 2018
|
@vext01 exactly, but I can see where that might cause confusion with 'real' modules. It might be surprising though that inside a function, OTOH, it's not really consistent how curly braces interact with scoping anyway. When defining an item or inside a function they introduce a namespace, but then we have |
This comment has been minimized.
This comment has been minimized.
|
Another piece of code I have in one of my projects is:
Is anyone aware of a more concise way to write this with current Rust, or is this another good use-case for this RFC? |
Centril
self-assigned this
Apr 19, 2018
This was referenced Apr 26, 2018
vext01
added some commits
Apr 27, 2018
vext01
changed the title
Item-level scopes.
Item-level blocks (was: Item-level *scopes*)
Apr 27, 2018
This comment has been minimized.
This comment has been minimized.
|
Thanks for everyones input. I've revised the RFC to include your comments. |
This comment has been minimized.
This comment has been minimized.
|
I feel a bit nervous about introducing blocks -- there is definitely the potential for confusion about the scoping. My inclination for the scenarios covered in this RFC is usually to make a module -- one could also imagine writing a macro (e.g., Perhaps the @rust-lang/libs team would like to weigh in with their experiences from libstd. |
This comment has been minimized.
This comment has been minimized.
|
I have a lot of experience from writing no_std compatible libraries (failure and futures) where the current best practice is to have a I think better than the status quo but also possibly better than just introducing arbitrary blocks is adding a built-in (someday a macro with the two-block syntax) like |
This comment has been minimized.
This comment has been minimized.
|
One thing I just remembered is there is one place that the I don't think this RFC as written could be used in that position, I'm not really sure whether the scope inside an |
This comment has been minimized.
This comment has been minimized.
|
In the interests of moving this forward: It sounds like the primary concern here is whether people will expect things declared inside a On the flip side, I do think the ability to have a block and apply attributes to it (starting with Given that, I do think it might make sense to wrap this in a built-in macro, taking the attribute (using standard attribute syntax) and the block as arguments. |
This comment has been minimized.
This comment has been minimized.
|
I would like the solution to allow scoping {
use some_crate::*;
fn i_use_tons_of_stuff() { ... }
}
fn i_dont() { /* can't accidentally refer to some_crate here */ }C++ provides us a little precedent here with anonymous namespaces, which are used largely for visibility, and provide an effect similar to implicitly declaring them at a previous level. Things declared inside the anonymous namespace, though not accessible from other translation units, act similarly to how they would if they were declared at the top-level. That said, C++ also now has inline namespaces, where However, bringing declarations up a level would also mean that you can't scope declarations to the block alone; they would necessarily be visible from the rest of the module (and thus from children). This feels a little bit unclean. To throw another bike at the shed, what if any item declared in an anonymous module with a mod {
pub(self) fn f() {}
fn h() {}
}
fn g() { f() } // ok
fn f() {} // not ok, f is already declared in this scope
fn i() { h() } // not ok, h is not visibleThe downside is the boilerplate, of course; since Rust has no way to explicitly make something less public, this becomes tricky. |
Centril
added
A-cfg
A-syntax
labels
Nov 22, 2018
Centril
added
the
I-nominated
label
Nov 29, 2018
This comment has been minimized.
This comment has been minimized.
|
Based on discussions among the language team, we mostly agreed that we'd like a way to reduce repetition of the same For that reason: However, we'd love to see a proposal that does not use braces, and still eliminates repetition, such as an attribute alias system, or some other syntax. |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Dec 20, 2018
•
|
Team member @joshtriplett has proposed to close this. The next step is review by the rest of the tagged teams:
No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
rfcbot
added
proposed-final-comment-period
disposition-close
labels
Dec 20, 2018
Centril
removed
the
I-nominated
label
Dec 20, 2018
This comment has been minimized.
This comment has been minimized.
|
I'm not sure I agree with the sentiment that |
This comment has been minimized.
This comment has been minimized.
graydon
commented
Jan 12, 2019
|
Oppose. This is what inline mods are there for. |
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jan 13, 2019
|
|
rfcbot
added
final-comment-period
and removed
proposed-final-comment-period
labels
Jan 13, 2019
rfcbot
added
finished-final-comment-period
and removed
final-comment-period
labels
Jan 23, 2019
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Jan 23, 2019
|
The final comment period, with a disposition to close, as per the review above, is now complete. By the power vested in me by Rust, I hereby close this RFC. |
vext01 commentedMar 29, 2018
•
edited
Hi,
This is a draft PR to address #2312.
rendered
This is my first contribution to this repo, so I may require some guidance WRT the process.
Fixes #2312
Thanks