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

Change inner attribute syntax for clarity and consistency #2569

Closed
brson opened this issue Jun 11, 2012 · 68 comments · May be fixed by devcode1981/rust#6 or MarcelRaschke/rust#6
Closed

Change inner attribute syntax for clarity and consistency #2569

brson opened this issue Jun 11, 2012 · 68 comments · May be fixed by devcode1981/rust#6 or MarcelRaschke/rust#6
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
Milestone

Comments

@brson
Copy link
Contributor

brson commented Jun 11, 2012

As discussed in #2568, the trailing semicolon to differentiate 'inner' from 'outer' attributes is not intuitive. Also, #2498 will add doc comments as a special form of attribute, which will differentiate 'inner' doc comments using doxygen's /**< */ syntax. To make inner attribute syntax more consistent with doc comments and more visually distinct I would like to change the inner attribute syntax to:

#<attribute>

The meaning would still be the same - it's an inner attribute - but in practice you would probably think of them as 'crate attributes' or 'module attributes' since they typically would appear at the top of files and apply to whatever the file represents.

No attribute is followed by a semicolon.


Added clarification for people visiting this bug in the future (e.g. for triage), mostly to explain the "inner" vs "outer" distinction, because that terminology is not used in the Rust manual: Currently attributes in Rust can either be terminated by a semi-colon, or they can leave out the semi-colon; the former denotes an "inner attribute", which applies to the (entire) entity that the attribute is declared within, and the latter denotes an "outer attribute", which must be followed by an entity (and applies solely to that entity).

This bug is discussing a number of alternatives to that syntax. Lets see if we can enumerate the proposals and how much interest they have garnered. (Most of the proposals keep the existing outer attribute syntax unchanged, but there is one exception, so I include it in my examples below.)

  1. (current) semi-colon inner: mod foo { #[outer(attr)] mod bar { #[inner(attr)]; } }
  2. brson's orginal angle-bracketed inner: mod foo { #[outer(attr)] mod bar { #<inner(attr)> } }
  3. bstrie leading exclamation inner: mod foo { #[outer(attr)] mod bar { #![inner(attr)] } }
  4. graydon nested exclamation inner: mod foo { #[outer(attr)] mod bar { #[!inner(attr)] } }
  5. brson bracket-less for both, leading exclamation inner: mod foo { #outer(attr) mod bar { #! inner(attr) } }
  6. bstrie bracketed-inner, bracket-less outer: mod foo { #outer(attr) mod bar { #[inner(attr)] } }
  7. pnkfelix semi-colon terminated bracket-less inner, bracketed outer: mod foo { #[outer(attr)] mod bar { #inner(attr); } }

Note also of course that we have indeed now switched to denoting macros with a trailing ! as discussed in the comments, which paves the way for the bracket-less forms.

@brson
Copy link
Contributor Author

brson commented Jun 11, 2012

This should make attribute parsing significantly simpler since there's a fixed amount of lookahead needed to know if you are parsing an inner attribute.

@graydon
Copy link
Contributor

graydon commented Jun 12, 2012

I'm ok with this but as mentioned in the other bug on doc comments, think angle-bracket might not be the most delicious choice. It's not really visually suggestive of what it applies to; the semi rule had that going for it (with the drawback being, I guess, both subtlety and no obvious connection to any doc-comment syntax).

Maybe something involving exclamation points or vertical bars? :)

@graydon
Copy link
Contributor

graydon commented Jun 12, 2012

(only half joking; we adopted shebang comments already and intend to have those around for tagging language-version. maybe you can dangle this function on a relative of that syntax)

@Dretch
Copy link
Contributor

Dretch commented Jun 12, 2012

I guess it has much the same issues, but how about ^ instead of < ?

@brson
Copy link
Contributor Author

brson commented Jun 12, 2012

@Dretch. I think ^ looks ok in comments but don't see a nice way to wedge it into the attribute syntax - #^[attribute], #^attribute^.

@bstrie
Copy link
Contributor

bstrie commented Jun 14, 2012

I'm surprised that graydon suggested the shebang notation, because I was going to suggest

#![module_level_attribute]
// as opposed to
#[function_level_attribute]

...but I thought people would think it was too silly. :) I still like it, though!

@graydon
Copy link
Contributor

graydon commented Jun 14, 2012

Yeah. I've poked at this long enough in my own emacs buffer now to feel positive about the bang-mark. It goes ok in comments too. Though to ensure we don't confuse any shell interpreters trying to run attributes, I think it should differ in first-two chars from shebang itself. I.e. move the bang inside the attribute. So we wind up with:


// shebang means 'run through this interpreter', like always
#!/bin/env rustc --run 

// leading sharp-comments in the root source file are scanned for pre-parsing control tags.
# rust: <compiler-uuid> <low-lang-version> <high-lang-version>

// bang-attrs apply to their containing item.
// in practice so far these seem to be module-level
// most of the time, so are "evocative" of shebang and
// pre-parse control tags, without being ambiguous with them
#[!warn(no_implicit_copies)]

// normal-attrs apply to the following item.
#[test]
fn test_patience() { ... }

// bang-comments are docstrings that apply to their enclosing item.

//! this is a one-liner.
/*! This is a
 *  multi-line one.
 */

// Common triple-slash and double-star doc-comments
// apply to the next item.

/// Magic number
const x = 10;

/** Very enjoyable
 *  function doc
 */
fn joy() {
}

Is this too ghastly? It looks ... ok to me. I mean, it's a stretch but we have a bunch of layers of functionality to get to hang together here and it'd be good to have it "work" nice.

(In theory we could also wedge-in a pre-parse conditional-compilation mode, via the plain-sharp coments, as an escape hatch for conditionally-compiling things that differ at only a lexeme-by-lexeme level. Sometimes the resolution of the #[cfg(...)] attribute is just not fine enough. Might be nice?)

@brson
Copy link
Contributor Author

brson commented Jun 14, 2012

The bang does look good. The main reason I didn't want to use it is because in doxygen /*! and /** mean the same thing, but it is the best looking alternative.

We should change the attribute grammer to only have one meta item per. This is something I've wanted to do anyway as a simplification, but I really don't want to be able to write #[!inner, outer]. Maybe #![inner] is less confusing.

The bang does strongly suggest logical negation though. What does #[!cfg(unix)] mean?

One thing that might impact attribute syntax is that pcwalton wants to change the extension grammer to be fmt! instead of #fmt, which I like. This would open more possibilities in the attribute grammer. Specifically, we can get rid of the brackets:

# cfg(unix)
fn foo() {
    #! cfg(unix)
}

Of course then you have to worry about distinguishing between attributes and a shebang.

@bstrie
Copy link
Contributor

bstrie commented Jun 14, 2012

I'm not sure that we need to resort to #[!. I'm having a hard time imagining any situation where the token #![ could begin a legal shebang (so it would always just throw an error), and since the only time this would ever be encountered would be if someone tried to ./their_rust_program, and since they'd need a valid shebang in that case regardless (and since shebangs can only occur on the first line of a file), I don't know if this could ever be an issue. Worse still, #[! would seem to collide with negation within attributes; does #[!cfg(target_os = "win32")] mean "don't do this on windows"?

Iff you are swayed by these arguments, I think a clearer rule for the docstrings and attributes would be "docstrings and attributes apply to the following item, unless their opening token is followed by a !". So you'd have:

#!/bin/env rustc --run
// for the set of people who like to run their programs directly,
// and thus will not be at all confused as to what a shebang is

#![module_level_attribute]
///! module-level one-line doc comment
/**! module-level
 *   multiline doc comment
 */

(New personal resolution: submit one unrelated-to-syntax patch for every bikeshedding comment I make.)

@bstrie
Copy link
Contributor

bstrie commented Jun 14, 2012

re: brson's comment (which wasn't here when I started typing the above): I really adore the bracketless notation, and also signifying macros with a trailing !. Once again, I don't think it would be at all hard to disambiguate with shebangs, since people who want to use shebangs will know what a shebang is, and since you can't stick / inside a valid rust identifier (and since shebangs must contain absolute rather than relative paths), and since (on bash at least) shebangs can only appear in the very first line of a file, so it's easy to test for.

(patch_debt++)

@z0w0
Copy link
Contributor

z0w0 commented Apr 23, 2013

I just got assigned this for the triage. I actually feel that the current syntax is more consistent than the suggested alternatives. Does anyone have strong feelings about this still?

@bstrie
Copy link
Contributor

bstrie commented Apr 23, 2013

@z0w0 I still have strong feelings that the existing trailing-semicolon-inner-attribute syntax is very bad, I just think there's been no real discussion of what to replace it with. Would be nice to bring this up on the mailing list and fish for comments.

@graydon
Copy link
Contributor

graydon commented Apr 23, 2013

I can live with any of the options, including present form. I think @brson still dislikes it though, and people do stumble on it regularly.

@metajack
Copy link
Contributor

My first choice is bracketless, followed by #!.

@z0w0
Copy link
Contributor

z0w0 commented Apr 23, 2013

Perhaps inline could be exclamation mark in front of the statement like !cfg(test) to match rustdocs crate level attributes and outer level macros could look like #cfg(test). The hashbang for inner macros just seems weird to me.

@bstrie
Copy link
Contributor

bstrie commented Apr 23, 2013

@metajack bracketless is also my favorite option, and I think brson has expressed some fondness for that form as well. The "lightness" of the bracketless syntax is very refreshing. And maybe we could then use bracketed syntax for inner attributes, as a visual shorthand to represent that those attributes are "enclosed".

#inline(always)
fn foo() {
    #[some_inner_thing]
    ...
}

@metajack
Copy link
Contributor

@bstrie at first glance +1

@brson
Copy link
Contributor Author

brson commented Apr 23, 2013

If we go with @bstrie's suggestion of bracketless vs brackets then we also need to consider how that relates to doc comments

# inline(always)
/// Do a foo
/** Do a foo */
fn foo() {
    #[some_inner_thing]
    //! Do a foo
    /*! Do a foo */
    ...
}

This solution hasn't particularly improved the syntactic relationship between attributes and doc comments. I might feel happiest making inner attributes #! some_inner_thing, but of course that doesn't work because of shebangs.

@bstrie
Copy link
Contributor

bstrie commented Apr 23, 2013

I don't think there's necessarily a need to draw parallels between doc comments and attributes, even if the former happens to be implemented in terms of the latter. Having two forms of doc comments has always just seemed silly. :)

Inner doc comments can do everything that outer ones can, yeah? At the risk of going out-of-scope, I'd propose getting rid of the bizarre //! and /*! forms, and converting inner doc comments over to the more-standard /// and /**. Python serves as a precedent here.

More generally speaking, I feel like having two different syntaxes for doc comments is needlessly decadent. Better to pick just one form and enforce it.

@graydon
Copy link
Contributor

graydon commented Apr 23, 2013

Inner for modules. We keep revisiting this :)

@brson
Copy link
Contributor Author

brson commented Apr 23, 2013

@bstrie the reasons for needing both doc comment forms are identical to the reason for needing both attribute forms. Doc comments are attributes.

I am though still open to figuring out a reliable way to make doc comments work with only a single syntax. Even I regularly use the wrong form of comments in places, and emacs still doesn't know how to word wrap //! comments.

@brson
Copy link
Contributor Author

brson commented Apr 23, 2013

Nominating.

@z0w0
Copy link
Contributor

z0w0 commented Apr 24, 2013

What about two hashes? ## inline(always).

@jbclements
Copy link
Contributor

I prefer the form with the delimiters. I'd like to see them go away altogether or be restricted to module-top-level, but it makes me sad when a perfectly serviceable delimiter notation gets axed.

@pnkfelix
Copy link
Member

@jbclements "I prefer the form with the delimiters" seems to contradict "I'd like to see them go away altogether"; is there a typo there?

Update: Okay, I now infer that you meant "I'd like to see inner attributes themselves go away entirely, or be restricted in where they can be used, but if one is going to keep them as a feature, then I'd prefer a bracketed syntax."

@pnkfelix
Copy link
Member

If we go with the shebang notation, I would prefer to also keep the trailing semi-colon. I want it to be clear to the human reader that this form is a significant independent entity and does not apply to the item that follows it. For example:
mod m { #![inner(attribute)]; fn foo() { ... } #[outer(attribute)] fn bar() { ... } }

This way, when one is scanning backwards, one can distinguish the two cases without having to look all the way at the beginning of the attribute declaration.

bors added a commit that referenced this issue Mar 21, 2014
This will require a snapshot to finish, but these commits update the parser to parse attributes of the form `#![...]`

Thanks to @thehydroimpulse for all the initial work!

cc #2569
alexcrichton pushed a commit to alexcrichton/rust that referenced this issue Mar 28, 2014
@brson brson closed this as completed in 451e8c1 Mar 29, 2014
Geal added a commit to Geal/glfw-rs that referenced this issue Apr 2, 2014
Applied fixes:
	*logging macros need the log crate
	*attribute fix (cf rust-lang/rust#2569)
	*priv attribute removal
	*Rename Chan to Sender (cf rust-lang/rust@7858065)
	*New vec library (cf rust-lang/rust#12771)
	*update the channel constructor (cf rust-lang/rust@7858065)
	*Rename Port to Receiver (cf rust-lang/rust@7858065)
Geal added a commit to Geal/rust-opencl that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*New vec library (cf rust-lang/rust#12771)
Geal added a commit to Geal/rust-zmq that referenced this issue Apr 2, 2014
Applied fixes:
	*priv attribute removal
	*attribute fix (cf rust-lang/rust#2569)
Geal added a commit to Geal/rust-statsd that referenced this issue Apr 2, 2014
Applied fixes:
	*priv attribute removal
	*attribute fix (cf rust-lang/rust#2569)
	*Rename Port to Receiver (cf rust-lang/rust@7858065)
	*logging macros need the log crate
Geal added a commit to Geal/boehm-rs that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
Geal added a commit to Geal/quick-check that referenced this issue Apr 2, 2014
Applied fixes:
	*extern mod is obsolete
	*attribute fix (cf rust-lang/rust#2569)
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
Geal added a commit to Geal/rs-persistent-datastructures that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*Rename Chan to Sender (cf rust-lang/rust@7858065)
	*New vec library (cf rust-lang/rust#12771)
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
	*Replace Freeze by Share (cf rust-lang/rust@12ecafb)
Geal added a commit to Geal/redis-rs that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*crate extra was removed
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
	*update the channel constructor (cf rust-lang/rust@7858065)
Geal added a commit to Geal/rust-msgpack that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*New vec library (cf rust-lang/rust#12771)
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
Geal added a commit to Geal/nphysics that referenced this issue Apr 2, 2014
Applied fixes:
	*attribute fix (cf rust-lang/rust#2569)
	*priv attribute removal (cf rust-lang/rust@f2a5c7a)
celinval pushed a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
Projects
None yet