Thread overview
Chaining opIndex
May 09, 2016
deed
May 09, 2016
John Colvin
May 10, 2016
deed
May 09, 2016
struct Foo {
    Bars bars;
    ...
}

struct Foos {
    Foo[] arr;
    Foo opIndex (size_t idx) { return arr[idx]; }
    ...
}

struct Bar {
    // No Car[] cars;
    ...
}

struct Bars {
    Bar[] arr;
    Bar opIndex (size_t idx) { return arr[idx]; }
    ...
}

struct Car {
    ...
}

Foos foos;
Foo foo = foos[1];                  // Works
Bar bar = foos[1].bars[2];          // Works
Car car = foos[1].bars[2].cars[3];  // Desired abstraction.

For any Bar there are some Cars, but Bar doesn't hold any Cars. In other words, there could be a function Car cars (Bar bar, size_t idx) { ... }, but that would be called with parens;

Car car = foos[i].bars[j].cars(k);

which would be inconsistent and confusing. Defining

struct Cars {
    Car opIndex (Bar bar, size_t idx) {}
}

and

struct Bar {
    Cars cars;
    ...
}

doesn't enable chaining and then would have to be used like this, AFAIK:

Car car = cars[foos[i].bars[j], k];

Which is out of the question. Any suggestions to achieve the desired abstraction in a clean manner?

May 09, 2016
On Monday, 9 May 2016 at 20:14:25 UTC, deed wrote:
> struct Foo {
>     Bars bars;
>     ...
> }
>
> struct Foos {
>     Foo[] arr;
>     Foo opIndex (size_t idx) { return arr[idx]; }
>     ...
> }
>
> struct Bar {
>     // No Car[] cars;
>     ...
> }
>
> struct Bars {
>     Bar[] arr;
>     Bar opIndex (size_t idx) { return arr[idx]; }
>     ...
> }
>
> struct Car {
>     ...
> }
>
> Foos foos;
> Foo foo = foos[1];                  // Works
> Bar bar = foos[1].bars[2];          // Works
> Car car = foos[1].bars[2].cars[3];  // Desired abstraction.
>
> For any Bar there are some Cars, but Bar doesn't hold any Cars. In other words, there could be a function Car cars (Bar bar, size_t idx) { ... }, but that would be called with parens;
>
> Car car = foos[i].bars[j].cars(k);
>
> which would be inconsistent and confusing. Defining
>
> struct Cars {
>     Car opIndex (Bar bar, size_t idx) {}
> }
>
> and
>
> struct Bar {
>     Cars cars;
>     ...
> }
>
> doesn't enable chaining and then would have to be used like this, AFAIK:
>
> Car car = cars[foos[i].bars[j], k];
>
> Which is out of the question. Any suggestions to achieve the desired abstraction in a clean manner?

There are lots of ways to approach this. Here's one possibility:

auto cars(Bar bar)
{
    static struct Res
    {
        Bar bar;
        Car opIndex(size_t i)
        {
            return /* e.g. getCar(bar, i); */
        }
    }
    return Res(bar);
}
May 10, 2016
On Monday, 9 May 2016 at 22:33:37 UTC, John Colvin wrote:
> There are lots of ways to approach this. Here's one possibility:
>
> auto cars(Bar bar)
> {
>     static struct Res
>     {
>         Bar bar;
>         Car opIndex(size_t i)
>         {
>             return /* e.g. getCar(bar, i); */
>         }
>     }
>     return Res(bar);
> }

Thanks. Didn't think of function returning struct with opIndex. Having this as opCall in a struct Cars might be a solution.

What other approaches did you have in mind?