Use statements are a bit unwieldy from time to time. I find myself wanting to follow some kind of rule for how to do my use statements. One problem is with useing many things from a single crate. For example:
use bincode::SizeLimit;
use bincode::rustc_serialize::{DecodingError, encode, decode};
I think it would be nice to be able to collapse this into a single use statement as follows:
use bincode::{
SizeLimit,
rustc_serialize::{
DecodingError,
encode,
decode
}
};
I know that not everyone will like this example, but the ability to have paths inside of the {, } form of the use statement would be a nice addition in many cases. This feature seemed so intuitive to me I honestly almost expected it to already work like this.
This would be nice.
I personally find it harder to scan, but that may be because I'm accustomed to separate use statements.
Overall, I think this would be a useful feature.
The one major complaint I have is that it requires more vertical scanning to determine what crate/module a type initially originates from.
@rphmeier I imagine that in practice this will actually make it easier to scan for what crate/module something is from. This is because one need only to search by indentation for the use statements inside each crate/module.
I've wanted this many times. This should also come with a style-guide requiring the indentation.
It's a pretty logical extension to https://github.com/rust-lang/rfcs/pull/1219 and it predecessors, I think it came up before. Something like
use_item = [::]tree_import;
tree_import = prefix::{(suffix,)*}
suffix = relative-path [as name] | relative-path::* | tree_import
maybe with some restrictions on self and super.
Name resolution happens _as if_ the import tree is flattened before resolving names.
One thing that can be perceived as a drawback is that this extension changes the look of imports quite heavily. For example, look at some file with lots of imports, like https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs
After reformatting it looks like:
Spoiler
pub use self::PathParsingMode::*;
use {
abi,
ast::{self, BareFnTy},
ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier},
ast::{Public, Unsafety},
ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue},
ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block},
ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause},
ast::{Constness, ConstTraitItem, Crate, CrateConfig},
ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn},
ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf},
ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain},
ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox},
ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace},
ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex},
ast::{ExprLit, ExprLoop, ExprMac, ExprRange},
ast::{ExprMethodCall, ExprParen, ExprPath},
ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary},
ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl},
ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy},
ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic},
ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst},
ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl},
ast::{ItemExternCrate, ItemUse},
ast::{LifetimeDef, Lit, Lit_},
ast::{LitBool, LitChar, LitByte, LitByteStr},
ast::{LitStr, LitInt, Local},
ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces},
ast::{MutImmutable, MutMutable, Mac_},
ast::{MutTy, BiMul, Mutability},
ast::{NamedField, UnNeg, NoReturn, UnNot},
ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange},
ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild},
ast::{PolyTraitRef, QSelf},
ast::{Return, BiShl, BiShr, Stmt, StmtDecl},
ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField},
ast::{BiSub, StrStyle},
ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue},
ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef},
ast::{Ty, Ty_, TypeBinding, TyMac},
ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer},
ast::{TyParam, TyParamBounds, TyParen, TyPath, TyPolyTraitRef, TyPtr},
ast::{TyRptr, TyTup, TyU32, TyVec},
ast::TypeTraitItem,
ast::{UnnamedField, UnsafeBlock},
ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple},
ast::{Visibility, WhereClause},
attr::{ThinAttributes, ThinAttributesExt, AttributesExt},
ast_util::{self, ident_to_path},
codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap},
diagnostic::{self, FatalError},
ext::tt::macro_parser,
parse::{
self, classify,
common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed},
lexer::{Reader, TokenAndSpan},
obsolete::{ParserObsoleteMethods, ObsoleteSyntax},
token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString},
token::{keywords, special_idents, SpecialMacroVar},
new_sub_parser_from_file, ParseSess, PResult
},
util::parser::{AssocOp, Fixity},
print::pprust,
ptr::P,
std::{
collections::HashSet,
io::prelude::*,
mem,
path::{Path, PathBuf},
rc::Rc,
slice
}
};
Personally, I like it better, but it's a big stylistic change.
actually as I understand it it would still be one use statement per top level import:
pub use self::PathParsingMode::*;
use abi;
use ast::{
self, BareFnTy,
RegionTyParamBound, TraitTyParamBound, TraitBoundModifier,
Public, Unsafety,
Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue,
BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block,
BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause,
Constness, ConstTraitItem, Crate, CrateConfig,
Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn,
UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf,
Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain,
ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox,
ExprBreak, ExprCall, ExprCast, ExprInPlace,
ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex,
ExprLit, ExprLoop, ExprMac, ExprRange,
ExprMethodCall, ExprParen, ExprPath,
ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary,
ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl,
ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy,
Ident, Inherited, ImplItem, Item, Item_, ItemStatic,
ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst,
ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl,
ItemExternCrate, ItemUse,
LifetimeDef, Lit, Lit_,
LitBool, LitChar, LitByte, LitByteStr,
LitStr, LitInt, Local,
MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces,
MutImmutable, MutMutable, Mac_,
MutTy, BiMul, Mutability,
NamedField, UnNeg, NoReturn, UnNot,
Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange,
PatRegion, PatStruct, PatTup, PatVec, PatWild,
PolyTraitRef, QSelf,
Return, BiShl, BiShr, Stmt, StmtDecl,
StmtExpr, StmtSemi, StmtMac, VariantData, StructField,
BiSub, StrStyle,
SelfExplicit, SelfRegion, SelfStatic, SelfValue,
Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef,
Ty, Ty_, TypeBinding, TyMac,
TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer,
TyParam, TyParamBounds, TyParen, TyPath, TyPolyTraitRef, TyPtr,
TyRptr, TyTup, TyU32, TyVec,
TypeTraitItem,
UnnamedField, UnsafeBlock,
ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple,
Visibility, WhereClause,
ThinAttributes, ThinAttributesExt, AttributesExt,
};
use ast_util::{self, ident_to_path};
use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap};
use diagnostic::{self, FatalError};
use ext::tt::macro_parser;
use parse::{
self, classify,
common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed},
lexer::{Reader, TokenAndSpan},
obsolete::{ParserObsoleteMethods, ObsoleteSyntax},
token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString},
token::{keywords, special_idents, SpecialMacroVar},
new_sub_parser_from_file, ParseSess, PResult,
};
use util::parser::{AssocOp, Fixity};
use print::pprust;
use ptr::P;
use std::{
collections::HashSet,
io::prelude::*,
mem,
path::{Path, PathBuf},
rc::Rc,
slice,
};
@oli-obk
Empty prefixes are already permitted, so they can be put into use if nested paths are allowed, so this is a purely stylistic choice.
I would hope the convention would be something like one use per top level though in general.
What about grouping the use statements as well?
use {
abi;
ast::{
self, BareFnTy,
RegionTyParamBound, TraitTyParamBound, TraitBoundModifier,
Public, Unsafety,
Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue,
BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, Block,
BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause,
Constness, ConstTraitItem, Crate, CrateConfig,
Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn,
UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf,
Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain,
ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox,
ExprBreak, ExprCall, ExprCast, ExprInPlace,
ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex,
ExprLit, ExprLoop, ExprMac, ExprRange,
ExprMethodCall, ExprParen, ExprPath,
ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary,
ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl,
ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy,
Ident, Inherited, ImplItem, Item, Item_, ItemStatic,
ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst,
ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl,
ItemExternCrate, ItemUse,
LifetimeDef, Lit, Lit_,
LitBool, LitChar, LitByte, LitByteStr,
LitStr, LitInt, Local,
MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces,
MutImmutable, MutMutable, Mac_,
MutTy, BiMul, Mutability,
NamedField, UnNeg, NoReturn, UnNot,
Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange,
PatRegion, PatStruct, PatTup, PatVec, PatWild,
PolyTraitRef, QSelf,
Return, BiShl, BiShr, Stmt, StmtDecl,
StmtExpr, StmtSemi, StmtMac, VariantData, StructField,
BiSub, StrStyle,
SelfExplicit, SelfRegion, SelfStatic, SelfValue,
Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef,
Ty, Ty_, TypeBinding, TyMac,
TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer,
TyParam, TyParamBounds, TyParen, TyPath, TyPolyTraitRef, TyPtr,
TyRptr, TyTup, TyU32, TyVec,
TypeTraitItem,
UnnamedField, UnsafeBlock,
ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple,
Visibility, WhereClause,
ThinAttributes, ThinAttributesExt, AttributesExt,
};
ast_util::{self, ident_to_path};
codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap};
diagnostic::{self, FatalError};
ext::tt::macro_parser;
parse::{
self, classify,
common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed},
lexer::{Reader, TokenAndSpan},
obsolete::{ParserObsoleteMethods, ObsoleteSyntax},
token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString},
token::{keywords, special_idents, SpecialMacroVar},
new_sub_parser_from_file, ParseSess, PResult,
};
util::parser::{AssocOp, Fixity};
print::pprust;
ptr::P;
std::{
collections::HashSet,
io::prelude::*,
mem,
path::{Path, PathBuf},
rc::Rc,
slice,
};
}
If ergonomics really is a focus in 2016, then this would be a relatively simple, but useful ergonomic addition.
Most helpful comment
If ergonomics really is a focus in 2016, then this would be a relatively simple, but useful ergonomic addition.