Opinions on syntax sugar for tuple-based indexing


#1

I couldn’t find any prior discussion on this subject, so I hope you don’t mind that I start it.

My main interest in Rust is for scientific computing, and specifically numerical mathematics, which means I work with matrices a lot. Currently, the available linear algebra crates (I’m mostly familiar with rulinalg and ndarray) index matrices (2d arrays) like this:

x[[i, j]]
// Or
x[(i, j)]

It’s not a very big deal, but the redundant brackets don’t exactly help readability when you’re dealing with algorithms that do complex patterns of indexing. Of course, it would be neat if one could instead do this:

x[i, j]

One very obvious way to accomplish this is to provide syntax sugaring when the index type is a tuple. That is,

x[i, j] becomes x[(i, j)]

The reason I want a tuple is that I want to be able to mix the types, so one could do things like

x[i, ..]

for retrieving the row of index i in the matrix.

Syntax sugaring tuples is only one way to accomplish this, but it seems the most straightforward from my own naive point of view, having little to no knowledge of Rust internals. My goal with this post is to get a feeling for what kind of opinions people have for this matter. In addition:

  1. Are there any technical reasons that would prohibit this kind of syntax sugaring?
  2. Are there any language-philosophical reasons that would prohibit this syntax sugar?
  3. Are there any other concerns with this?

I’d be very interested to hear some view points. Thanks!


#2

What bothers me about this is that it’s a non-obvious, invisible transform. Also, there’s a better solution: variadic generics. That would allow Index to be changed (hopefully in a backward-compatible fashion) to:

pub trait Index<Idx...> where Idx: ?Sized {
    type Output: ?Sized;
    fn index(&self, index: Idx...) -> &Self::Output;
}

That would let you implement indexing for any arity, including zero. Plus, this extends the “rewrite a list into a tuple” idea to everything, rather than just indexing.


#3

Thanks for your insight! I agree that this is a much better solution. If this is possible to do in a backward-compatible manner, it is certainly worth waiting for.

The discussion on variadics seems to have stalled a little, but it seems it’s such a desired feature that I hope it will eventually be implemented. In that case, the question of whether the changes to Index can be made in a backwards compatible manner seem to be the main question of interest with regards to variadic indexing. Is it possible to determine the answer to this already?


#4

For certain? Probably not. In broad terms, though, it should be relatively straightforward. All it would do is make invocations like Index<A, B> or Index::index(&a, x, y) legal where they currently aren’t. Even existing implementations shouldn’t be affected, since they’re just implementing the case for one index type.

If there are problems, I’d expect them to come from anything relying on the precise definition of Index, like code that replaces or re-implements core traits, or is trying to do some kind of perfect forwarding.

But, really, there are so many things it’d be great to have, we’ll just have to be patient.


#5

But, really, there are so many things it’d be great to have, we’ll just have to be patient.

Yes, of course. I realize this feature is probably towards the end of a long line of gingerly awaited features. Personally I’m far more concerned with e.g. type-level integers in generic code and generic specialization, but whereas these features have been discussed a lot, I could not really find any discussion on the topic of (now variadic) indexing.

Thanks for explaining!


#6

Sadly, variadic generics like that are a pain to implement, and we would probably have to resort to desugaring it to Index[T: Tuple] where Index<A, B, C> becomes Index[(A, B, C)] (imagine T[X] was an internal representation that both Foo<T> and Fn(A) desugared to).

That said, if we pick a desugaring like that, all existing code should still work, as only Index[(Idx,)] would ever get implemented (and assuming coherence doesn’t ruin the party).