Indexing a single element tuple struct

Single element tuple structs fit many uses, such as the NewType pattern explained in the Rust Book where a type defined elsewhere is extended with custom traits or methods. (can they be used to restrict against usage of methods as well?)

When indexing into a single element tuple struct, you must use syntax to indicate which element is being indexed, e.g. my_var.0. This seems redundant, and this also implies that there are other elements present.

How possible would it be to remove the redundant indexing? A potential problem I could think of is assignment: let my_var2 = my_var which would have unclear semantics of whether the tuple struct is being assigned or the variable within the tuple struct was being assigned. However, assignment of the variable within the tuple struct seems like an unusual use case, which would be a case where an explicit indexing my_var.0 would be required.

I would like it if I could define a single element tuple struct to not require extra indexing.

While I recognize and agree it's a pain for the new type pattern, e.g:

pub struct MyType(SomeOneElsesType);

It's also the case that the entire point of a such a construct is usually to distinguish the wrapper type from the enclosed type. You choose the privacy of the inner type, the trait implementations of the outer type, etc. Using var.0 doesn't make sense when the field is private to your code, or when the outer type implements some trait you're trying to utilize and the inner type doesn't. So there would need to be some new syntax for "no really, I want the outer type" to "negate" the automatic .0, which would be just as annoying as .0 is. And when they both implement a trait, which one do you want? What happens to existing code when you add a new trait impl, or the underlying type does?

The compiler can't guess intent, and while annoying at times, consistency is going to be a lot less confusing than some implicit rule which doesn't even apply all the time and may even change depending on your privacy context, implemented traits, etc.

4 Likes

If you implement Deref and/or DerefMut for your struct, then you can use *x instead of x.0 to refer to the inner value. Also, you can access methods or fields of the inner value using implicit dereferencing, like x.foo() and x.bar().

Note that these traits will make the inner type accessible everywhere, so they are not useful if you want to keep such access private.

Or you could use a struct with a named field like struct MyType { inner: Foo }, if you find x.inner to be clearer than x.0. (You can choose any name you like for the field, of course.)

6 Likes