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

Allow multiple crates in one `extern crate` declaration. #167

Closed
wants to merge 1 commit into from

Conversation

Projects
None yet
10 participants
@liigo
Copy link
Contributor

liigo commented Jul 16, 2014

  • Start Date: 2014-07-16
  • RFC PR #: (leave this empty)
  • Rust Issue #: (leave this empty)

Summary

Allow multiple crates in one extern crate declaration.

Motivation

To make the source code more compact, and be consistent with use declaration, which allow use multiple types/functions in one line (one declaration).

Detailed design

Instead of having to write:

extern crate collections;
extern crate flate;
extern crate libc;
extern crate log;
extern crate num;
extern crate regex;
extern crate serialize;
extern crate test;

... the programmers could be allowed to write these in one line:

extern crate collections, flate, libc, log, num, regex, serialize, test;

The new syntax EBNF would be:

extern_crate_decl : "extern" "crate" crate_list ;
crate_list : ident [ '(' link_attrs ')' ] ? [ '=' string_lit ] ? [ ',' crate_list ] + ;
link_attrs : link_attr [ ',' link_attrs ] + ;
link_attr  : ident '=' literal ;

After this change, the source code is more compact, but still keep clean, concise and readable.

Drawbacks

Lexer syntax will be a little more complex.

Alternatives

Use the { } syntax of use declaration:

extern crate {collections, flate, libc, log, num, regex, serialize, test};

which is a little fussy.

Unresolved questions

None.

@sinistersnare

This comment has been minimized.

Copy link

sinistersnare commented Jul 16, 2014

Thanks for writing this up, I have been meaning to myself.

+1 for with or without braces.

maybe for when we do extern crate mycrate = "myothercrate"; it has to be its own statement, and can not be nested using the proposed syntax?

@sinistersnare

This comment has been minimized.

Copy link

sinistersnare commented Jul 16, 2014

Also: original issues rust-lang/rust#11811 and rust-lang/rust#11819

@sinistersnare

This comment has been minimized.

Copy link

sinistersnare commented Jul 16, 2014

And final questions from that thread:

  • How are attributes handled?
#![feature(phase)]
#[phase(plugin)]
extern crate regex_macros, collections;
  • How are doc comments handled?
/** These are glorious docs*/
extern crate foo, bar, baz;
@sfackler

This comment has been minimized.

Copy link
Member

sfackler commented Jul 16, 2014

Doc comments attached to an extern crate statement are ignored in general.

@bharrisau

This comment has been minimized.

Copy link

bharrisau commented Jul 16, 2014

Maybe I don't write enough (or use enough extern crates when I do), but I really don't feel like this change is worth it. Trying to jam several crates into one line makes it much less readable.

I feel the biggest benefit is with #[cfg] as it lets you group them together.

@chris-morgan

This comment has been minimized.

Copy link
Member

chris-morgan commented Jul 16, 2014

👎 I don’t like this; it just doesn’t feel nice, just as use foo, bar; would not feel nice.

Python is a language where you can do this sort of thing, but it is considered bad form—PEP 8 forbids import a, b, for example (equivalent to use a, b; and/or extern crate a, b;, while allowing from a import b, c (equivalent to use a::{b, c}). Due to the way our use, mod and extern crate things tie together, the reason it makes sense for Python to support such a thing from a grammar perspective has not applied to us, and we do not presently support it. I do not believe we gain anything by adding this additional form; things are clearer without it.

@liigo

This comment has been minimized.

Copy link
Contributor Author

liigo commented Jul 16, 2014

@bharrisau extern crate a, b, c, d, e; lists the crates one by one, it's obviously readable. I don't kown why you say "much less readable".

@chris-morgan You don't gain anything by copying extern crate many times.

@bharrisau

This comment has been minimized.

Copy link

bharrisau commented Jul 16, 2014

@liigo Maybe it is just me, I just have a harder time scanning extern crate bar, baz, bam, bad, ban, boo; than

extern crate bar;
extern crate baz;
extern crate bam;
extern crate bad;
extern crate ban;
extern crate boo;
@lucy

This comment has been minimized.

Copy link

lucy commented Jul 16, 2014

Using { and } would make this:

extern crate {
    foo,
    bar,
    baz,
};

natural, which currently works with use.

@liigo

This comment has been minimized.

Copy link
Contributor Author

liigo commented Jul 16, 2014

Harris, we always read articles/words from left to right, I don't think
it's harder to scan.

@sinistersnare

This comment has been minimized.

Copy link

sinistersnare commented Jul 16, 2014

@lucy Why should the following not work?

extern crate foo,
    bar,
    baz,
    qux;
@lucy

This comment has been minimized.

Copy link

lucy commented Jul 16, 2014

@sinistersnare It does, but doesn't read as well (in my opinion), or like any other things in the language (as far as I know). The form with braces would be closer to other "lists" like structs, enums and use statements. Allowing a comma after the last crate in that—so that inserting, removing and reordering crates can be done easily—also seems problematic.

@DiamondLovesYou

This comment has been minimized.

Copy link

DiamondLovesYou commented Jul 19, 2014

+1 for

extern crate { foo = "bar", bar = "foo" };

I feel this could be delayed till post-1.0, though.

@sinistersnare

This comment has been minimized.

Copy link

sinistersnare commented Jul 20, 2014

If someone else can implement it who is not on the core team, why postpone it.

@pczarn

This comment has been minimized.

Copy link

pczarn commented Jul 20, 2014

we always read articles/words from left to right, I don't think it's harder to scan.

I can remember research that has found narrow columns of text (as in newspapers) to be easier to read. Even though they aren't optimal in terms of average reading speed.

a weak -1

@liigo

This comment has been minimized.

Copy link
Contributor Author

liigo commented Jul 21, 2014

@pczarn

I can remember research that has found narrow columns of text (as in newspapers) to be easier to read. Even though they aren't optimal in terms of average reading speed.

The current Rust code style for column limit is 100, you can narrow it to 80, even 40. That is just another topic. When I extern 8 crates in one line, it just 73 columns:

extern crate collections, flate, libc, log, num, regex, serialize, test;

and you are free to rewrite it:

extern crate collections, flate, libc, log;
extern crate num, regex, serialize, test;
@Kimundi

This comment has been minimized.

Copy link
Member

Kimundi commented Jul 31, 2014

+1 For the extern crate {foo, bar, baz}; form, its more consistent with use, and I'd like to see those two item types share as much common syntax for common properties as possible for consistency and usability.

@bharrisau

This comment has been minimized.

Copy link

bharrisau commented Jul 31, 2014

extern crate is used only at the beginning of a crate. use is used at the beginning of a module. A crate usually has between 0 and 10 extern crate, whereas there are many more use.

Is there some compelling reason for this change that I'm not seeing? Given the interactions with extern crate renaming, and the general 'expense' of having an external dependency, this feels like a solution in search of a problem.

There is no consistency issue with use, they are already different and this will just complicate extern crate more than simplifying extern crate/use dynamics.

@liigo

This comment has been minimized.

Copy link
Contributor Author

liigo commented Aug 1, 2014

To make it more consistent and clearer, is the reason. This change do
not complicate
the language, but simplify it, from users perspective, IMO.

Is there some compelling reason to keep verbose and non-consistent?

@Kimundi

This comment has been minimized.

Copy link
Member

Kimundi commented Aug 6, 2014

@bharrisau: While its true that you never write many extern crate lines, and hence this change is not a pressing issue, it would in my opinion simplify the syntax by making extern crate and use share the common aspects of it. Both may be different, but not that different:

  • Both make a name visible in the local scope
  • Both can be written in a module

The main difference is that

  • extern crate only brings modules in scope, while use can bring modules, types, statics, etc
  • extern crate only takes a single identifier, compared to the path use takes

But in both cases its the same operation: "Take this name, and make something in the local scope reachable through it". For use this can be batched with {}, for extern crate not, which seems inconsistent.

Weaker differences are

  • extern crate can not be pub. I'd actually argue that this should be changed for consistency as well (and in fact i recently had a case where that would have been useful to do). But thats a different RFC
  • extern crate is recommended to be written in the crate root. However, as long as the language does not enforce this, I don't see it as a relevant reason against unifying the syntax.
@bharrisau

This comment has been minimized.

Copy link

bharrisau commented Aug 7, 2014

Except we also have extern crate foo = "bar", soon to be extern crate bar as foo. And commonly #[cfg(not(test))] #[phase(plugin)] extern crate foo and the like. So they are already pretty different.

But it is a minor issue - I do believe it will do more harm than good, but I'm not going to kick and scream about it either way.

@Kimundi

This comment has been minimized.

Copy link
Member

Kimundi commented Aug 7, 2014

Heh, true, there are quite a few more differences than common properties between those two item types. :)

However, those lay in the side effects or source of the elements referenced. What they have in common is the effect on the current module, which, like the syntax, is what the developer of the module actually has to work with.

As an example, the two lines in mod foo would be identical as far as the module system is concerned, and be convenient to write for small projects:

mod foo {
    extern crate {core, regex};
    use {mycore, myregex};
}
mod mycore;
mod myregex;

extern crate "bar" as foo just selects a non-identifier name as a source, which does not affect the name created, and the attribute case is the same as with use ...::{...} today: Either it applies to all, or its a compile error, on a per-attribute basis.


That said, this is a purely backwards-compatible change, so I wouldn't be surprised if this does not get decided on one way or another before 1.0, and till then a lot can still change that could change my reasoning here.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Aug 14, 2014

This is a minor feature without a lot of agreement about whether it's desirable, and since it's backwards compatible, we want to not do it now. If it continues to be a pain point we can revisit.

@brson brson closed this Aug 14, 2014

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017

wycats pushed a commit to wycats/rust-rfcs that referenced this pull request Mar 5, 2019

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.