Skip to content

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

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
thestinger opened this issue Apr 11, 2013 · 17 comments
Closed
Labels
A-grammar Area: The grammar of Rust P-low Low priority

Comments

@thestinger
Copy link
Contributor

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.

@sethfowler
Copy link

Thanks for opening this issue, @thestinger!

@catamorphism
Copy link
Contributor

Nominating for milestone 2, backwards-compatible

@bblum
Copy link
Contributor

bblum commented Jun 20, 2013

this is a great issue; i endorse it

@graydon
Copy link
Contributor

graydon commented Aug 22, 2013

accepted for backwards-compatible milestone

@glaebhoerl
Copy link
Contributor

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

@brson
Copy link
Contributor

brson commented Nov 1, 2013

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] => { }
    }
}

@brendanzab
Copy link
Member

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);

@brson
Copy link
Contributor

brson commented Nov 1, 2013

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

@brson
Copy link
Contributor

brson commented Nov 1, 2013

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

@brendanzab
Copy link
Member

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

@brson
Copy link
Contributor

brson commented Nov 1, 2013

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

@brendanzab
Copy link
Member

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.

@nikomatsakis
Copy link
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]

@brson
Copy link
Contributor

brson commented Nov 8, 2013

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.

bors added a commit that referenced this issue Nov 19, 2013
This replaces `*` with `..` in enums, `_` with `..` in structs, and `.._` with `..` in vectors. It adds obsolete syntax warnings for the old forms but doesn't turn them on yet because we need a snapshot.

#5830
@alexcrichton
Copy link
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.

@pnkfelix
Copy link
Member

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

@alexcrichton
Copy link
Member

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

flip1995 pushed a commit to flip1995/rust that referenced this issue Jul 26, 2020
trait_sel: only test predicates w/ no substs

r? @ghost
changelog: none
calebcartwright pushed a commit to calebcartwright/rust that referenced this issue Oct 23, 2023
* Use matches!() macro to improve readability

1. Use `matches!()` macro in `is_line_comment` and `is_block_comment` to
improve readability.
2. Very sightly improve the wording of the doc comment for these two functions.

* Update wording on doc comment on is_line_comment()
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-grammar Area: The grammar of Rust P-low Low priority
Projects
None yet
Development

No branches or pull requests