Search code examples
arraysindexingrusttupleslanguage-lawyer

Did the Designers of Rust ever publicly say why the syntax of indexing an array is different to indexing a tuple?


In Rust a tuple can be indexed using a dot (e.g.: x.0), while an array can be indexed with square brackets (e.g.: x[0]). At first glance this seems to me as if it would make it harder to refactor existing code, without serving any actual purpose. However, I am probably just missing something. Did the creators of Rust ever comment on this and told us why they chose to build the language that way?


Solution

  • This tuple field access syntax was introduced in RFC 184 (discussion thread). Before that, you had to destructure all tuples (and tuple structs) to access their values, or use special traits in the standard library.

    The RFC itself does not go into a lot of detail regarding the alternative [index] syntax, but the discussion thread does. I see three main reasons why we ended up with the .index syntax:

    [] is related to std::ops::Index

    The [index] syntax is strongly related to the ops::Index trait. It allows you to overload that operator for your own types. The way the trait is designed, the index method (which is called when you use []) has to return that same type every time. So ops::Index cannot be used for heterogeneous types. And since [] is very related to the trait, it might be strange to have a few special usages of [] that don't use std::ops::Index.

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

    Comment

    Indexing syntax [is] actually a really bad fit. Notably, indexing syntax everywhere else has a consistent type, but a tuple is heterogenous so a[0] and a[1] would have different types.

    Comment

    Tuples/tuple structs as structs with anonymous fields

    Rust has other heterogeneous data types: structs. And you access their fields with the .field syntax. And describing tuple structs as structs with unnamed fields, and describing tuples as unnamed tuple structs, it makes sense to treat both a bit like structs. Then, the .0 just feels like referencing an unnamed field.

    I feel, especially in statically-typed languages, the types of a[1], a[2], ..., a[N] should be the same.

    Yes, that's why nobody is advocating for adding indexing syntax to tuples. The tuple.1 syntax is a much better fit; it's basically anonymous field access, rather than indexing.

    Comment

    Tuples and tuple structs are just structs with anonymous fields ordered by their definition, so both should support syntax for accessing a field as an lvalue directly to make working with them more consistent and easier.

    Comment

    Influenced by Swift

    Swift already had that syntax and seems to have been an influence:

    For reference, Swift allows this tuple indexing syntax, and allows for assignment with it.

    Comment

    +1 swift has a lot of nice pragmatic tweaks, and this is one of them, IMO.

    Comment

    thanks to swift there's going to be a large community familiar with the .0 .1 ... notation

    Comment


    As an aside: as can be seen by this thread, the "designers of Rust" really are, for the most part, just the community members. Sure, the RFC process had its problems back then (and it's still not perfect), but you can read most of that discussion online, with community members commenting on the proposed syntax.