Thread overview
opIndexDispatch?
Oct 10, 2016
Yuxuan Shui
Oct 10, 2016
Jonathan M Davis
Oct 12, 2016
Yuxuan Shui
Oct 12, 2016
Jonathan M Davis
Oct 13, 2016
Yuxuan Shui
Oct 13, 2016
Ali Çehreli
Oct 14, 2016
Marc Schütz
Oct 14, 2016
Jonathan M Davis
October 10, 2016
Hi,

Why is there no opIndexDispatch for overloading a[x].func() ?
October 10, 2016
On Monday, October 10, 2016 19:01:19 Yuxuan Shui via Digitalmars-d-learn wrote:
> Hi,
>
> Why is there no opIndexDispatch for overloading a[x].func() ?

There's opIndex for overloading a[x], and then you can call a function on the return value. If you want some kind of opDispatch on the return value, then the return type will need to implement opDispatch.

- Jonathan M Davis

October 12, 2016
On Monday, 10 October 2016 at 19:16:06 UTC, Jonathan M Davis wrote:
> On Monday, October 10, 2016 19:01:19 Yuxuan Shui via Digitalmars-d-learn wrote:
>> Hi,
>>
>> Why is there no opIndexDispatch for overloading a[x].func() ?
>
> There's opIndex for overloading a[x], and then you can call a function on the return value. If you want some kind of opDispatch on the return value, then the return type will need to implement opDispatch.
>
> - Jonathan M Davis

The opIndex* overloads are used for handling the case where the key is not already in the data structure, right?
October 12, 2016
On Wednesday, October 12, 2016 22:45:28 Yuxuan Shui via Digitalmars-d-learn wrote:
> On Monday, 10 October 2016 at 19:16:06 UTC, Jonathan M Davis
>
> wrote:
> > On Monday, October 10, 2016 19:01:19 Yuxuan Shui via
> >
> > Digitalmars-d-learn wrote:
> >> Hi,
> >>
> >> Why is there no opIndexDispatch for overloading a[x].func() ?
> >
> > There's opIndex for overloading a[x], and then you can call a function on the return value. If you want some kind of opDispatch on the return value, then the return type will need to implement opDispatch.
> >
> > - Jonathan M Davis
>
> The opIndex* overloads are used for handling the case where the key is not already in the data structure, right?

opIndex is for overriding the subscript operator so that you can do stuff like foo[bar]. What you actually make the function do is up to you. It could require that the element already be there. It could add the element if it's not there. It could even do something completely unrelated to indexing (though that would generally be considered bad practice). But aside from syntax, the requirements on it are largely just convention. It's good practice to make indexing act similarly to what you'd expect from a built-in type such as an array or associative array, but that's not actually enforced.

opIndexUnary, opIndexAssign, and opIndexOpAssign exist to make it possible to do some basic operations on the result of foo[bar] without having to have opIndex return by ref, but assuming that you can return by ref, all of them could be done by having opIndex return by ref. If you were just wrapping an array or trying to mimic an array, then there's a decent chance that you'd just make opIndex return by ref and not overload the others, whereas in the case of something like an associative array, using opIndexAssign makes more sense, because the only way for opIndex to return by ref when opIndex creates the element is if it's default-initialized, whereas if opIndexAssign is used, it can just be created directly with the new value.

If you're looking to be able to use opDispatch on the return value without returning by ref and while still affecting something within the object being indexed rather than just affecting the temporary that would be returned by opIndex, then you'll have to do something like return a type that has a pointer to the object being indexed and which implements opDispatch so that foo[bar].baz() uses opDispatch and still is able to acess foo via the pointer in the return value from foo[bar]. There is no opIndexDispatch to combine opIndex and opDispatch.

- Jonathan M Davis

October 13, 2016
On Wednesday, 12 October 2016 at 23:14:26 UTC, Jonathan M Davis wrote:
> opIndexUnary, opIndexAssign, and opIndexOpAssign exist to make it possible to do some basic operations on the result of foo[bar] without having to have opIndex return by ref, but assuming that you can return by ref, all of them could be done by having opIndex return by ref.

No? If I want to mimics opIndex* by having opIndex return a ref. I would need to create a new entry every time opIndex is used to access a non-existent key, whether the return value is used as a lvalue or not. And opIndex* will solve this problem.
October 12, 2016
On 10/10/2016 12:01 PM, Yuxuan Shui wrote:
> Hi,
>
> Why is there no opIndexDispatch for overloading a[x].func() ?

I could not understand the question fully but would using an element proxy work?

import std.stdio;

struct ElementProxy {
    size_t index;

    void opDispatch(string name, Args...)(Args args) {
        writefln("%s() is called for index %s with args %s", name, index, [ args ]);
    }
}

struct A {
    auto opIndex(size_t index) {
        return ElementProxy(index);
    }
}

void main() {
    auto a = A();
    a[0].foo(42);
    a[1].bar("hello", "world");
}

Prints

foo() is called for index 0 with args [42]
bar() is called for index 1 with args ["hello", "world"]

Ali

October 14, 2016
On Thursday, 13 October 2016 at 01:09:06 UTC, Ali Çehreli wrote:
> On 10/10/2016 12:01 PM, Yuxuan Shui wrote:
>> Hi,
>>
>> Why is there no opIndexDispatch for overloading a[x].func() ?
>
> I could not understand the question fully but would using an element proxy work?
>

I assume a proxy would indeed work, but it's indeed inconsistent. A proxy would work for opIndexAssign() and friends as well, so why do they exist, when opIndexDispatch() doesn't?
October 14, 2016
On Friday, October 14, 2016 09:09:33 Marc Schütz via Digitalmars-d-learn wrote:
> On Thursday, 13 October 2016 at 01:09:06 UTC, Ali Çehreli wrote:
> > On 10/10/2016 12:01 PM, Yuxuan Shui wrote:
> >> Hi,
> >>
> >> Why is there no opIndexDispatch for overloading a[x].func() ?
> >
> > I could not understand the question fully but would using an element proxy work?
>
> I assume a proxy would indeed work, but it's indeed inconsistent.
> A proxy would work for opIndexAssign() and friends as well, so
> why do they exist, when opIndexDispatch() doesn't?

Presumably, because it  didn't occur to anyone when the others were added. And most stuff implementing opIndex is likely to have it return by ref. But opDispatch is kind of a weird beast to begin with. There are a few cases where it's really useful, but in general, it's not used much. And I'm pretty sure it's one of the overloaded operators that was added later on given that most of them existed in different forms before we used templated functions with strings for overloaded operators, whereas opDispatch requires a compile-time string. So, when the decision to add the opIndex* functions in addition to opIndex was made, opDispatch probably hadn't even been proposed yet.

- Jonathan M Davis