I believe this falls victim to the same problem that GATifying the
Index trait falls into: the
arr[ix] syntax is not sugar for a function call. It's much more complicated than that.
The result of an expression
arr[ix] is, in Rust terminology, a place. (In C++ terms, an lvalue.) In Rust, this isn't a "thing" that you can return from a function or bind in a binding, so it's kind of difficult to talk about. (In C++, you can have an lvalue reference,
T&, which makes this kind of discussion easier. In fact, in C++, indexing is just sugar for a function returning an lvalue reference (with overloading semantics).) A place is effectively "what you get from a dereference operator".
What makes a place special is that while it's typed at
T, you can use it without moving the value. When you take a reference to a place, you get the same reference that was dereferenced to obtain the place.
So, okay, indexing is sugar for not
*arr.index(ix), so that you can take it's address with
&mut,,, and it... somehow decides whether to call
index_mut instead, if you "use the place via mutable reference".
And this interaction with the context is what really drives the nail in the coffin of returning anything other than references from index, imho. You could maybe get around the immediate dereference by just saying that
&arr[ix] returns your special handle, rather than a regular reference, and the same for
But how do you resolve method syntax?
.method() can either use the place by-move, by-ref, or by-mut. This is resolved by the signature of
T::method and what the receiver type is, and then that receiver type is back-propagated to decide whether to call
There is no way to resolve this for custom handle types. The behavior of indexing syntax is tied to the details of returning built-in references in order to be a place expression and act how people expect.
I'm pretty sure I said it the last time I talked about this, but I really should submit a design notes document for "why
Index can't be GATified".
And now I have to note that you've somewhat sidestepped this issue with the OP. Notably, you've:
- Used a theoretical mutually exclusive trait to the
Index trait, avoiding
Index compatibility hazards;
&mut access to the indexee, avoiding resolution concerns;
- Mandated returning a (boxed dyn future returning an) owned value, avoiding the problem of returning a place; and
- Hidden complexity behind
#[async_trait] (though this (async fn in traits) is a likely future feature).
So maybe my whole rant about GAT
Index doesn't apply. But I think the spirit of the issue remains:
Index is special, and your
IndexAsync isn't special, it's just a regular function call.
So really, the question stands: why should this be put on the
 syntax, when it behaves quite unlike the existing
 syntax? If your goal isn't to produce a place, what you want is a function call.