Thread overview
When to opCall instead of opIndex and opSlice?
Oct 02
Nordlöw
October 02
Is implementing opCall(size_t) for structures such as array containers that already define opIndex and opSlice deprecated?

I can't find any documentation on the subject on when opCall should be defined to enable foreach (isIterable).
October 02
On 2017-10-02 17:57, Nordlöw wrote:
> Is implementing opCall(size_t) for structures such as array containers that already define opIndex and opSlice deprecated?
> 
> I can't find any documentation on the subject on when opCall should be defined to enable foreach (isIterable).

opCall is not related to foreach. It's used to overload the call operator, i.e. ().

struct Foo
{
    void opCall() {};
}

Foo foo;
foo();

Are you thinking of opApply [1]?

[1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes

-- 
/Jacob Carlborg
October 02
On Monday, 2 October 2017 at 18:14:24 UTC, Jacob Carlborg wrote:
> On 2017-10-02 17:57, Nordlöw wrote:
>> Is implementing opCall(size_t) for structures such as array containers that already define opIndex and opSlice deprecated?
>> 
>> I can't find any documentation on the subject on when opCall should be defined to enable foreach (isIterable).
>
> opCall is not related to foreach. It's used to overload the call operator, i.e. ().
>
> struct Foo
> {
>     void opCall() {};
> }
>
> Foo foo;
> foo();
>
> Are you thinking of opApply [1]?
>
> [1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes

Ahh, yes of course.

It seems like defining opIndex anf opSlice is enough in the array container case. Why do we have opApply as well? Non-random access?
October 02
On Monday, October 02, 2017 18:31:23 Per Nordlöw via Digitalmars-d-learn wrote:
> On Monday, 2 October 2017 at 18:14:24 UTC, Jacob Carlborg wrote:
> > On 2017-10-02 17:57, Nordlöw wrote:
> >> Is implementing opCall(size_t) for structures such as array containers that already define opIndex and opSlice deprecated?
> >>
> >> I can't find any documentation on the subject on when opCall should be defined to enable foreach (isIterable).
> >
> > opCall is not related to foreach. It's used to overload the
> > call operator, i.e. ().
> >
> > struct Foo
> > {
> >
> >     void opCall() {};
> >
> > }
> >
> > Foo foo;
> > foo();
> >
> > Are you thinking of opApply [1]?
> >
> > [1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes
>
> Ahh, yes of course.
>
> It seems like defining opIndex anf opSlice is enough in the array container case. Why do we have opApply as well? Non-random access?

opApply was the original way to implement the ability to use foreach with user defined types. Later, when ranges were added to the language, foreach was made to try slicing the type, and if that resulted in a range, then that was used with foreach. So, opSlice made it possible to use foreach (but only if the result was a range), and later opIndex was altered to also do what opSlice does.

opApply is kept around in part to avoid breaking any code and in part because there are cases where implementing foreach that way rather than with a range is more efficient. IMHO, it also makes more sense in cases where you're dealing with a transitive front - e.g. if std.stdio's byLine were implemented via opApply and you _had_ to use byLineCopy when you wanted a range, then we'd have avoided a lot of problems with byLine - though at least we do now have byLineCopy instead of just byLine, even if byLine still returns a range.

Random access has nothing to do with foreach in any of those cases, because random access isn't ever used with foreach and user-defined types. The closest you get is when you use index with foreach, and that works with arrays (but not ranges) and with opApply. So, it's probably using random access on arrays when iterating over them, but it doesn't with ranges in general, and it doesn't with opApply unless the underlying implementation happens to use random access inside of opApply; opApply itself isn't designed to use random access any more than front and popFront are.

- Jonathan M Davis


October 02
On 10/2/17 2:31 PM, Per Nordlöw wrote:
> On Monday, 2 October 2017 at 18:14:24 UTC, Jacob Carlborg wrote:
>> On 2017-10-02 17:57, Nordlöw wrote:
>>> Is implementing opCall(size_t) for structures such as array containers that already define opIndex and opSlice deprecated?
>>>
>>> I can't find any documentation on the subject on when opCall should be defined to enable foreach (isIterable).
>>
>> opCall is not related to foreach. It's used to overload the call operator, i.e. ().
>>
>> struct Foo
>> {
>>     void opCall() {};
>> }
>>
>> Foo foo;
>> foo();
>>
>> Are you thinking of opApply [1]?
>>
>> [1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes
> 
> Ahh, yes of course.
> 
> It seems like defining opIndex anf opSlice is enough in the array container case. Why do we have opApply as well? Non-random access?

First, it should be front, popFront, and empty, not opIndex and opSlice.

Second, opApply has existed forever (even in D1). Ranges are more recent.

Third, opApply has some characteristics that are difficult to implement via ranges.

-Steve