Pre-RFC: Allow 0,1,2,... as "identifier" in structs

Not sure this even needs a RFC, but pre-RFC was the most fitting title.

I would be happy to work on the implementation - if this is deemed a wanted change.

I am not sure I understand the reasoning why this is not allowed:

struct Foo {
    0: i32, // This is the only thing that fails ...
    arg_1: i32,
    named_1: i32,
}

fn main() {
    let foo = Foo { 0: 0, arg_1: 1, named_1: 42} ;
    println!("{}", foo.0);
}

fails only at the struct definition with "^ expected identifier". Would it not just be necessary to change 'IDENTIFIER' to 'IDENTIFIER_OR_NUMBER' (pseudo-code wise)?

to make it all work as everything else seems to be able to work with '.0', '0: ', etc.?

I am also not seeing the drawback given that it is already inconsistent right now.

My personal motivation with that is to mirror named function arguments in structs as they then perfectly match the:

0: arg_0, 1: arg_1, named_1: arg_3

pattern. Also getting this change (0: as allowed identifier in structural records) in independent of structural records is one less thing that structural records need to handle - and it is planned as part of their RFC. (https://github.com/rust-lang/rfcs/pull/2584/files/051686558a1b57448193fbc2938f1a3f193e9c7e#diff-82f56a33e385fa4523376256280d53cfR635-R646)

To be precise: I am only suggesting to allow numbers as identifiers, nothing else - so there is still plenty of distinction from Tuple to Struct, but they can be 1:1 mapped, but as for every other identifier you need to be explicit about the 0, 1, ...:

Tuple (i32, i32) ~= Struct { 0: i32, 1: i32 }

[They are not equal, just mappable]

If you haven't seen it already, for this part you'd probably be interested in https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md#tuple-structs

Tuple structs really are "just" structs with integer members; this works:

#[derive(Debug)]
struct Tuple(usize, usize);

fn main() {
    let tuple = Tuple { 0: 0, 1: 1 };
    let Tuple { 0: _, 1: _ } = tuple;
    dbg!(tuple);
}

However, I fail to see the concrete benefit to allowing mixing numbered fields and named fields. To be completely honest, were Rust to not have tuple structs (nominal product types with indexed fields) yet (but ignoring their use in enums), I could definitely see them not being motivated enough to add to the languagenote 1.

This is a lot of rambling to basically say: you need more/better motivation. You can make the argument for consistency since the "numbered fields" syntax is allowed for accessing fields and braced patterns for tuple structs, but tuple structs are already special (the function call pattern) so it's not like this would make tuple structs just sugar over braced structs.

This could potentially be argued as a reasonable extension to the language, but there needs to be some reasonable effort put into motivation beyond just the consistency angle, imho. In addition, questions like what integer literals are allowed (do they have to be continuous, start at zero, can they come after named fields, etc) have to be answered.

Also,

is probably not what you're actually suggesting; that'd mean allowing e.g. let 0 = "Hello, world!"; print(0); with 0 as an identifier meaning let zero = "Hello, world!"; print(zero); You don't want integer literals ad identifers, but to allow integer literals as struct field names (in more places).

note 1 again, ignoring enums. Enums are weird conglomerates of both (type theoretical) sum types and product types, and if we only had the braced variant enum E { Variant { name: Data } } form, I can definitely see quickly moving to add in the tuple variants there, and once tuple variants exist, allowing them as full tuple structs instead as well as variants. But perhaps this magical theoretical Rust without tuple structs has "purer" sum type enumerations, where each variant is a tag associated to some existing type, rather than being its own product type?

7 Likes