Rfcs: Nested Paths in Use Statements

Created on 9 Dec 2015  ·  10Comments  ·  Source: rust-lang/rfcs

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.

T-lang

Most helpful comment

If ergonomics really is a focus in 2016, then this would be a relatively simple, but useful ergonomic addition.

All 10 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

3442853561 picture 3442853561  ·  3Comments

burdges picture burdges  ·  3Comments

rust-highfive picture rust-highfive  ·  4Comments

yongqli picture yongqli  ·  3Comments

3442853561 picture 3442853561  ·  3Comments