Is there any technical reason Rust is designed to use dot notation for tuples instead of using index notation (t[2]
)?
let t = (20u32, true, 'b')
t.2 // -> 'b'
Dot notation seems natural in accessing struct's and object's properties. I couldn't find a resource or explanation online.
The reason for using
t.2
syntax instead oft[2]
is best explained in this comment:I had no part in the design decisions, but here's my perspective:
Tuples contain mixed types. That is, the property
type_of(t[i]) == type_of(t[j])
cannot be guaranteed.However, conventional indexing works on the premise that the
i
int[i]
need not be a compile-time constant, which in turn means that the type oft[i]
needs to be uniform for all possiblei
. This is true in all other rust collections that implement indexing. Specifically, rust types are made indexable through implementing the Index trait, defined as below:So if you wanted a tuple to implement indexing, what type should
Self::Output
be? The only way to pull this off would be to makeSelf::Output
an enum, which means that element accesses would have to be wrapped around a uselessmatch t[i]
clause (or something similar) on the programmer's side, and you'll be catching type errors at runtime instead of compile-time.Furthermore, you now have to implement bounds-checking, which is again a runtime error, unless you're clever in your tuple implementation.
You could bypass these issues by requiring that the index by a compile-time constant, but at that point tuple item accesses are pretending to behave like a normal index operation while actually behaving inconsistently with respect to all other rust containers, and there's nothing good about that.
I want to provide an answer from my experience using a functional language (Ocaml) for the while since I've posted this question.
Apart from @rom1v reference, indexing syntax like
a[0]
everywhere else also used in some kind of sequence structure, of which tuples aren't. In Ocaml, for instance, a tuple(1, "one")
is said to have typeint * string
, which conforms to the Cartesian product in mathematics (i.e., the plane is R^2 = R * R). Plus, accessing a tuple bynth
index is considered unidiomatic.Due to its polymorphic nature, a tuple can almost be thought of as a record / object, which often prefer dot notation like
a.fieldName
as a convention to access its field (except in language like Javascript, which treats objects like dictionaries and allows string literal access likea["fieldname"]
. The only language I'm aware of that's using indexing syntax to access a field is Lua.Personally, I think syntax like
a.(0)
tends to look better thana.0
, but this may be intentionally (or not) awkward considering in most functional languages it is ideal to pattern-match a tuple instead of accessing it by its index. Since Rust is also imperative, syntax likea.10
can be a good reminder to pattern-match or "go use a struct" already.This decision was made in RFC 184. The Motivation section has details:
The discussion in the associated pull request is also useful.