Skip to content

syntax: destructuring structs, tuple structs and tuples should be consistent #5830

Closed

Description

@thestinger

These are minor nitpicks, but they might as well be fixed before it's too late.

struct Foo(int, int, int, int);
struct Bar{a: int, b: int, c: int, d: int};

Ignoring all the fields is inconsistent:

let Foo(*) = Foo(5, 5, 5, 5);
let Bar(_) = Bar{a: 5, b: 5, c: 5, d: 5};

It doesn't seem like it's currently possible to ignore all fields of a regular tuple.

I think this would be nicer:

let Foo(*) = Foo(5, 5, 5, 5);
let Bar(*) = Bar{a: 5, b: 5, c: 5, d: 5};
let (*) = (5, 5, 5, 5);

With a struct, you can ignore "the rest", but you can't with a tuple struct or tuple:

let Bar{b: b, _} = Bar{a: 5, b: 5, c: 5, d: 5};

This would be more consistent, and similar to destructuring fixed-size vectors:

let Foo(a, b, *) = Foo(5, 5, 5, 5);
let Foo(*, d) = Foo(5, 5, 5, 5);
let (a, b, *) = (5, 5, 5, 5);
let (*, c, d) = (5, 5, 5, 5);
let Bar{b: b, *} = Bar{a: 5, b: 5, c: 5, d: 5};

An underscore would mean ignoring one field.

Activity

  1. sethfowler commented on Apr 11, 2013

    @sethfowler

    Thanks for opening this issue, @thestinger!

  2. catamorphism commented on May 24, 2013

    @catamorphism
    Contributor

    Nominating for milestone 2, backwards-compatible

  3. bblum commented on Jun 20, 2013

    @bblum
    Contributor

    this is a great issue; i endorse it

  4. graydon commented on Aug 22, 2013

    @graydon
    Contributor

    accepted for backwards-compatible milestone

  5. glaebhoerl commented on Aug 22, 2013

    @glaebhoerl
    Contributor

    How about .. instead of *? Already has the matches multiple fields connotation.

  6. brson commented on Nov 1, 2013

    @brson
    Contributor

    Here's a more complete test case. The stuff that's not commented out works (and probably shouldn't), and the stuff that's commented out should.

    struct Foo(int, int, int, int);
    struct Bar{a: int, b: int, c: int, d: int}
    
    fn main() {
        let Foo(*) = Foo(5, 5, 5, 5);
        //let Bar(*) = Bar{a: 5, b: 5, c: 5, d: 5};                                                                                                                                  
        let Bar{_} = Bar{a: 5, b: 5, c: 5, d: 5};
        //let (*) = (5, 5, 5, 5);                                                                                                                                                    
        //let Foo(a, b, *) = Foo(5, 5, 5, 5);                                                                                                                                        
        //let Foo(*, d) = Foo(5, 5, 5, 5);                                                                                                                                           
        //let (a, b, *) = (5, 5, 5, 5);                                                                                                                                              
        //let (*, c, d) = (5, 5, 5, 5);                                                                                                                                              
        //let Bar{b: b, *} = Bar{a: 5, b: 5, c: 5, d: 5};                                                                                                                            
        let Bar{b: b, _} = Bar{a: 5, b: 5, c: 5, d: 5};
        /*match [5, 5, 5, 5] {                                                                                                                                                       
            [a, *] => { }                                                                                                                                                            
        }*/
        /*match [5, 5, 5, 5] {                                                                                                                                                       
            [*, b] => { }                                                                                                                                                            
        }*/
        /*match [5, 5, 5, 5] {                                                                                                                                                       
            [a, *, b] => { }                                                                                                                                                         
        }*/
        match [5, 5, 5] {
            [a, .._] => { }
        }
        match [5, 5, 5] {
            [.._, a] => { }
        }
        match [5, 5, 5] {
            [a, .._, b] => { }
        }
    }
  7. brendanzab commented on Nov 1, 2013

    @brendanzab
    Contributor

    Tuples:

    let Tup(.._) = Tup(1, false);
    let (first, second, ..middle, last) = (1, "hi", false, 2, 3.0);
    assert_eq!(first, 1);
    assert_eq!(second, "hi");
    assert_eq!(middle, (false, 2));
    assert_eq!(last, 3.0)

    Structs:

    let Struct { .._ } = Struct { b: true, s: "hi", i: 23, f: 2.0 };
    
    // Error, 'rest' cannot be named in structs
    let Struct { x, ..end } = Struct { b: true, s: "hi", i: 23, f: 2.0 };
    
    let Struct { s: s, i: i, .._ } = Struct { b: true, s: "hi", i: 23, f: 2.0 };
    assert_eq!(s, "hi");
    assert_eq!(i, 2.0);
    
    let Struct { b, s, .._, f } = Struct { b: true, s: "hi", i: 23, f: 2.0 };
    assert_eq!(b, true);
    assert_eq!(s, "hi");
    assert_eq!(f, 2.0);
  8. brson commented on Nov 1, 2013

    @brson
    Contributor

    If we wanted to use * as a generic pointer deref pattern it would make the parser simpler to use ...

  9. brson commented on Nov 1, 2013

    @brson
    Contributor

    The semantics of using .. for pulling out tuples is complicated. With vectors it's (surely) just a slice.

  10. brendanzab commented on Nov 1, 2013

    @brendanzab
    Contributor

    I would also add that for structs its a little ugly, so yeah - not sure. Just an idea.

  11. brson commented on Nov 1, 2013

    @brson
    Contributor

    If we did go with .. then I would want just .. to mean 'everything else', not .._.

  12. brendanzab commented on Nov 1, 2013

    @brendanzab
    Contributor

    You could just remove the ability you destructure the tail for tuples, and go with:

    let (first, second, .., last) = ...;
    let Struct { s: s, i: i, .. } = ...;

    Either way, going with .. is fits nicer with vector destructuring, and reduces the amount of overloading on *, which is already under strain.

  13. nikomatsakis commented on Nov 2, 2013

    @nikomatsakis
    Contributor

    +1 for ..

    For that matter, in vector patterns, we could probably make the _
    implicit if the next token is a comma or closing brace etc. i.e.,
    [a, b, .., d]

  14. brson commented on Nov 8, 2013

    @brson
    Contributor

    I'm going to make the existing syntax consistent with .. and open a separate issue for adding .. to tuples and tuple-structs, since that's a deeper change that I don't know if I want to tackle personally.

  15. added a commit that references this issue on Nov 19, 2013
  16. alexcrichton commented on Nov 29, 2013

    @alexcrichton
    Member

    Renominating for demilestoning. We now have consistent "ignore the rest of these elements" across all patterns except for ignoring multiple fields in tuples (and tuple-like enum variants). We can always add those parts later (it's a backwards-compatible change), and I'm not sure that 1.0 should block on adding those features.

    Additionally, I think this bug should be closed in favor of a new one which is up to date with the current state of affairs.

  17. pnkfelix commented on Dec 19, 2013

    @pnkfelix
    Contributor

    Switching to P-low because its almost done, and the only thing(s?) remaining are back-compat and low priority for post-1.0.

  18. alexcrichton commented on Mar 12, 2014

    @alexcrichton
    Member

    Closing in favor of #10365, which is what remains to be done.

  19. added a commit that references this issue on Jul 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-grammarArea: The grammar of RustP-lowLow priority

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions