Should we make `nested_tuple.0.0` legal syntax?

Currently nested_tuple.0.0 is not legal and gives the following error

error: unexpected token: `0.0`
 --> src/lib.rs:2:19
  |
2 |     let x = nested_tuple.0.0;
  |             ------^^^
  |             |     |
  |             |     unexpected token
  |             help: try parenthesizing the first index: `(tuple.0).0`

error: aborting due to previous error

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Could we change this behavior to parse it as (nested_tuple.0).0 instead?

I assume that this could only be done if we are fine with not parsing 0. in a future edition, see this thread for discussion about that


This idea was spawned by @jethrogb in the thread about not parsing 0. float literals

8 Likes

I think use of the .0 syntax should be discouraged in general, so I don't feel a need to improve it. Personally, I try to avoid even single-level anonymous fields, because they make the code hard to follow:

x.0 = y.1 + 2;

I try to use destructuring instead, which allows naming the fields:

let (width, height) = tuple;

and that's clearer than:

tuple.0, tuple.1

So in this case I'd use:

let ((x, y), ..) = named_tuple;
1 Like

This might be easier as a poll

Should we allow yhis syntax?

  • Yes
  • No

0 voters

1 Like

Just to be paranoid: I voted on the assumption that "only after we rework number literal type inference" counts as a "yes" for your poll.

2 Likes

This doesn't have to do with number type inference, so that doesn't matter. However, I think we should do this after we sort out if we are going to make 0.-like float literals a hard error in future editions. But even if we don't make it a hard error, I still think we should do this. This is because floating point fields identifiers doesn't make sense because floating point weirdness (like NaN and -0.0 != 0.0), so this is the only reasonable interpretation of the syntax.

I don’t see how this has anything to do with whether 0. is legal.

3 Likes

As s.x.x is legal syntax, t.0.0 should be legal syntax for reasons of orthogonality?

Yes, that's the idea

Just to add a bit of technical information:

The lexer sees name.0.0 and spits out [(Ident "name") (Punct ".") (Lit "0.0")]. In order to make this a valid parse, "all" that has to happen is the parser has to learn to accept a float literal as a key for a place (like it does for integer literals already) as a nested tuple access. Alternatively, it can learn to split apart the float literal token in this specific case.

How does name.0.name lex and parse today? Naively, I'd expect the 0. to be lexed as a float currently. (On mobile, can't check.)

a.0.b parses without issue, and gives the expected result of accessing field 0 of a and then field b of a.0

Special cased in the lexer: https://github.com/rust-lang/rust/blob/ea52be482ab4945fda63cb65b6a198309a041e3c/src/librustc_lexer/src/lib.rs#L453-L457

5 Likes

As long as you don't allow name.0.1 to be written as name.1e-1 :wink:

12 Likes

Yes please, make this happen. It's a small, annoying ergonomic bug that I stub my toe on fairly regularly. I agree with @kornel that destructuring is generally a better idea, but there are times when I'm writing masses of tests and just using the number notation is easier. In some cases (niche ones) it is also easier, like when you've got a fixed-size vector/matrix and are treating the numbers as indexes.

1 Like

Given the overwhelming majority of people wanting this feature as per the poll above, I will see what I can do to make this happen!

5 Likes

I prefer your syntax too, but sometimes the compiler generates worse code; I don't have an example at hand but I remember that many times I used to look at the assembly and see that setting let x = y; and then using x would generate copying instructions even if y is not used any more.

Rustfmt transforms this code:

let a = (((1, 2), 3), 4);
let _ = a . 0 . 0 . 0;

to this:

let a = (((1, 2), 3), 4);
let _ = a.0 .0 .0;

I don't find it particularly annoying.

Although I agree that destructuring is often more elegant, I see no good reason to forbid writing name.0.0. It's an inconsistency that adds friction when writing code. I was quite surprised when I found out that it doesn't work.

2 Likes