Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: Tuple indexing #184
Conversation
pczarn
reviewed
Jul 24, 2014
|
|
||
| ```rust | ||
| let x = (box 1i, box 2i); | ||
| let x1 = { let (ref a, _) = x; a }; |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Wouldn't it be better to write a struct at the point you want to store and extract values from a tuple as a conglomerate? As I understand it, tuples are only really useful as a light-weight way of moving multiple values out of (and sometimes into) functions. Allowing |
This comment has been minimized.
This comment has been minimized.
|
I would actually rather like |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
@dhardy You cannot write a macro like that. Macros don't know about types, so you cannot construct a proper destructuring pattern for the tuple. Even if you could, such a macro could then not produce an lvalue to allow for assignment, which I believe this syntax should allow, e.g. let mut x = (1u, 2i, '3');
x.0 = 42u;For reference, Swift allows this tuple indexing syntax, and allows for assignment with it. |
This comment has been minimized.
This comment has been minimized.
|
@kballard I don't think Rust should include features just because Swift does. I agree with CM on this. |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
Jul 24, 2014
|
+1 swift has a lot of nice pragmatic tweaks, and this is one of them, IMO. this would be particularly useful with tuple-structs. There area times when the name of the type , and the types or positions of the components are sufficient information, and field names are just clutter. (vica versa, I would also like to see anonymous structs, but more ergonomic tuple structs would cover some of those cases). tuple structs also have the draw that the constructor is nice, but the repulsion that they're currently awkward to use (you must repeat the typename for destructuring). you can roll accessors with a macro but they also clutter your code and make it look more expensive than it is (and those macro definitions are another dependancy for libraries) Tangential but related, Committing to names before you've explored a problem is tiresome |
This comment has been minimized.
This comment has been minimized.
netvl
commented
Jul 24, 2014
|
+1. This would be very convenient, especially, as others have already said, with tuple structs. |
This comment has been minimized.
This comment has been minimized.
|
Incidentally, I don't think it makes sense to define this RFC in terms of the equivalent destructuring code. That just raises questions on edge cases that haven't been considered (or even not-so-edge cases, like assignment to a tuple index). I think it makes much more sense just to define tuple indexing as equivalent to using named fields, so the first field in a tuple implicitly has the field name |
This comment has been minimized.
This comment has been minimized.
|
Big Indexing on tuple structs makes the newtype idiom much easier to write. I'd be able to replace all those ugly |
This comment has been minimized.
This comment has been minimized.
FWIW, you can get this now by just using a normal struct with a field name: |
This comment has been minimized.
This comment has been minimized.
Yep. I think this is the right idea, and the proposal is just closing a features gap with respect to |
glaebhoerl
reviewed
Jul 24, 2014
| tuple structs. This syntax is recognised wherever an integer or float literal is | ||
| found in place of the normal field or method name expected when accessing fields | ||
| with `.`. Float literals in this position are expanded into two field accesses, | ||
| so that an expression of the form `a.1.3` is equivalent to `(a.1).3`. |
This comment has been minimized.
This comment has been minimized.
glaebhoerl
Jul 24, 2014
Contributor
I agree that a.1.3 should be legal and equivalent to (a.1).3, but isn't there a way to do this without introducing the awkwardness of float literals in the first place? I.e. just say that valid tokens following the . operator are either an identifier (named struct field, method) or a decimal number? And a.1.3 is just the same thing occuring twice.
This comment has been minimized.
This comment has been minimized.
Pythoner6
Jul 25, 2014
@glaebhoerl I would imagine (I am not well aquainted with the internals of the rust compiler) that float literals become involved because this RFC would probably be implemented by modifying the parser, whereas float literals are a type of token output by the lexer (since the lexer typically doesn't have much of a notion of context).
This comment has been minimized.
This comment has been minimized.
glaebhoerl
reviewed
Jul 25, 2014
|
|
||
| Allow indexing of tuples and tuple structs: this has the advantage of | ||
| consistency, but the disadvantage of not being checked for out-of-bounds errors | ||
| at compile time. |
This comment has been minimized.
This comment has been minimized.
glaebhoerl
Jul 25, 2014
Contributor
As also pointed out on reddit, indexing as such (i.e. tuple[0], tuple[1] etc.) wouldn't make sense as an alternative, because tuples are heterogenous. (They definitely couldn't be made to implement the Index* traits.)
This comment has been minimized.
This comment has been minimized.
bachm
commented
Jul 25, 2014
|
|
This comment has been minimized.
This comment has been minimized.
|
@bachm: yes, it improves the ergonomics of using tuples—but do we want to be doing that? I do not believe that we should be: such techniques are not good for code readability; I believe that they should always (yes, always—I will not even use |
This comment has been minimized.
This comment has been minimized.
bachm
commented
Jul 26, 2014
|
@chris-morgan yes, that also make sense from a certain point of view. However, currently |
This comment has been minimized.
This comment has been minimized.
|
@bachm: I would say it the other way round: we have |
This comment has been minimized.
This comment has been minimized.
pczarn
commented
Jul 26, 2014
|
Tuples and structs are not as alike as you think. Tuples probably can't have layout optimization. They are heterogeneous sequences, not records for accessing fields. |
This comment has been minimized.
This comment has been minimized.
Valloric
commented
Jul 26, 2014
|
I have to say @chris-morgan has a good point. In my experience, people tend to overuse tuples to the point where it hurst readability. A struct with named fields is almost always a better idea, and in Rust we have destructuring which makes pulling out relevant parts of tuples from a function returning a tuple really easy. So while this change is an ergonomic improvement, by implementing it we might be steering people to sub-par designs. |
This comment has been minimized.
This comment has been minimized.
The argument that a feature can be abused to write code with bad readability, and that therefore, it's better to not have the feature, is unpersuasive to me in general. It's true of most features. I prefer to leave issues of style and taste up to the programmer, because "one size fits all" rules generally don't. The proper avenues for encouraging good style, in my opinion, are through example-setting, cultural norms, education & community pressure, style guides for individual projects, etc. I.e. not by restricting the expressiveness or convenience of the language itself. People can write this today:
yet, remarkably, they don't. A solid argument against the feature is if you believe that it's outright never a good idea to use it (as I think @chris-morgan might), in which case I would like to see some compelling evidence or reasoning to back that up. |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
Jul 26, 2014
|
If you could destructure 'self', in the signature, that might remove some of the demand for this feature. but thanks to swift there's going to be a large community familiar with the .0 .1 ... notation One nice thing about tuples is avoiding needing to manage a dependancy. if two libraries use a common structure, which should own it ? - they can make themselves compatible without clashing on a declaration |
This comment has been minimized.
This comment has been minimized.
|
@chris-morgan |
This comment has been minimized.
This comment has been minimized.
|
Tuple structs (and tuple variants) are also annoying because they are very On Sun, Jul 27, 2014 at 11:49 AM, Kevin Ballard notifications@github.com
|
This comment has been minimized.
This comment has been minimized.
bluss
commented
Jul 27, 2014
|
With Indexing traits finally on board, I've implemented matrices that index by tuples -- |
This comment has been minimized.
This comment has been minimized.
Yeah, in most cases you'll want a named field. But sometimes you don't. Most obvious case is multiple return values from a function; generally you'll want a tuple, not a struct. |
This comment has been minimized.
This comment has been minimized.
omasanori
commented
Jul 28, 2014
|
I agree with @chris-morgan.
Indeed but we can use patterns to name each values, as already noted in the Alternatives section. let (quot, rem) = num::div_rem(n, m);
println!("The remainder is {}.", rem);
// vs
let res = num::div_rem(n, m);
println!("The remainder is {}.", res.1);The latter is shorter but I prefer the former for readability. Also, an example by @kballard: let mut x = (1u, 2i, '3');
x.0 = 42u;It is cool but I prefer using variables and constructing a tuple when we need it (to pass to a function, as a return value, etc.) |
This comment has been minimized.
This comment has been minimized.
So do that. I'm not suggesting that you should be storing local values in a tuple. That snippet is not supposed to represent real code but instead supposed to demonstrate a reduction of real code. Fundamentally, a tuple is a heterogenous fixed-length collection. Similarly, an array is a homogenous fixed-length collection. Why should the latter allow indexing but not the former? |
This comment has been minimized.
This comment has been minimized.
|
@omasanori You’ve made me realise another point in favour of this RFC. If a function returns a tuple, quite often only one value of that tuple is needed. Your println!("The remainder is {}.", num::div_rem(n, m).1);This is obviously not a good example, because one can just use Now even if there aren’t many functions that return tuples (I don’t know how many there are), a feature like this could allow more functions that return tuples. Right now a function that returns a tuple can be quite difficult to use—one must assign each value in a Personally, I think that the best alternative (or even complement) to this RFC would be anonymous structs. They are a great way to give names to return values without having to define a whole new struct (std::str::CharRange is a good example of a struct which I consider unnecessary). However, unless we get anonymous structs, the best way to describe (in code) what values are in a tuple is to put the descriptions in the name of the function itself: |
This comment has been minimized.
This comment has been minimized.
omasanori
commented
Jul 28, 2014
|
@kballard Thank you for clarification. @P1start It sounds good but personally I still prefer let (_, rem) = num::div_rem(n, m);style. Indeed such shorthands must be loved by some people, though. Anonymous structs might be good too, |
This comment has been minimized.
This comment has been minimized.
Yes, that's why nobody is advocating for adding indexing syntax to tuples. The |
This comment has been minimized.
This comment has been minimized.
|
FWIW, I just attempted to use a tuple-struct containing a Sample code: struct TupleStruct<'a>(&'a mut String);
impl<'a> TupleStruct<'a> {
fn inner(&mut self) -> &mut String {
let TupleStruct(ref mut s) = *self;
// the following complains that the lifetime of `s` is too short
&mut **s
}
}Edit: Figured it out: struct TupleStruct<'a>(&'a mut String);
impl<'a> TupleStruct<'a> {
fn inner(&mut self) -> &mut String {
let TupleStruct(&ref mut s) = *self;
s
}
} |
This comment has been minimized.
This comment has been minimized.
|
+1 from me. |
This comment has been minimized.
This comment has been minimized.
|
I’ve made a functioning prototype implementation of this in my |
This comment has been minimized.
This comment has been minimized.
|
I've been wanting to propose something like this for a while. I much prefer |
This comment has been minimized.
This comment has been minimized.
|
Also: I'd rather not change the lexer to permit a.0.1. I'd rather just have that be an error and have people write out the names. We could always add it later. |
This comment has been minimized.
This comment has been minimized.
|
Discussed in https://github.com/rust-lang/meeting-minutes/blob/master/weekly-meetings/2014-08-26.md @P1start please ammend the RFC to remove the surface grammar that converts floats to field access (but do leave a note about the compromise). This is a complexity that we don't believe is worth contorting the grammar for. Also please add a feature gate ('tuple_indexing' perhaps). |
This comment has been minimized.
This comment has been minimized.
|
@brson I’ve amended the RFC. |
P1start
referenced this pull request
Aug 30, 2014
Merged
Implement tuple and tuple struct indexing (RFC 53) #16866
This comment has been minimized.
This comment has been minimized.
|
@P1start thanks! |
brson
merged commit 9f146c1
into
rust-lang:master
Sep 3, 2014
This comment has been minimized.
This comment has been minimized.
|
Merged as RFC 53. Tracking bug: rust-lang/rust#16950 |
This comment has been minimized.
This comment has been minimized.
asterite
commented
Sep 4, 2014
|
I think adding a new syntax for this is unnecessary. This should work: let mut x = (1u, 2i);
let y = x[0];
x[0] = 2u;No need to add new syntax. But, the semantic checker must know that Pros:
Cons:
|
This comment has been minimized.
This comment has been minimized.
|
@asterite Indexing syntax was already commented upon, and rejected, because it's actually a really bad fit. Notably, indexing syntax everywhere else has a consistent type, but a tuple is heterogenous so |
P1start commentedJul 24, 2014
Rendered view