Thread overview
enumerated iteration to struct
Feb 07, 2018
Fra Mecca
Feb 07, 2018
Fra Mecca
Feb 07, 2018
Jonathan M Davis
Feb 07, 2018
Seb
February 07, 2018
I don't know if this post belongs to the learn section, but I'll try anyway.

I am using the std.path.pathSplitter function that returns a PathSplitter function exposing ranges primitive.

I have some question that could be generalized to other structs that expose range primitives.

1. Why can't I write foreach(i, el; pathSplitter("foor/bar").enumerate)  ?
2. Supposing I want to fix this problem, what do I add to the struct? opApply?
3. Why doesn't ranges infer the iteration method at compile time so that I don't need to write enumerate?
February 07, 2018
On Wednesday, 7 February 2018 at 01:10:34 UTC, Fra Mecca wrote:
> I don't know if this post belongs to the learn section, but I'll try anyway.
>
> I am using the std.path.pathSplitter function that returns a PathSplitter function exposing ranges primitive.
>
> I have some question that could be generalized to other structs that expose range primitives.
>
> 1. Why can't I write foreach(i, el; pathSplitter("foor/bar").enumerate)  ?
> 2. Supposing I want to fix this problem, what do I add to the struct? opApply?

There was a stupid stupid error on my part because I wasn't import the range module.

> 3. Why doesn't ranges infer the iteration method at compile time so that I don't need to write enumerate?

This question is still valid.
I think it would be saner to write
foreach(idx, el; paths)
instead of
foreach(idx, el; paths.enumerate)
February 06, 2018
On Wednesday, February 07, 2018 01:21:16 Fra Mecca via Digitalmars-d-learn wrote:
> On Wednesday, 7 February 2018 at 01:10:34 UTC, Fra Mecca wrote:
> > I don't know if this post belongs to the learn section, but I'll try anyway.
> >
> > I am using the std.path.pathSplitter function that returns a PathSplitter function exposing ranges primitive.
> >
> > I have some question that could be generalized to other structs that expose range primitives.
> >
> > 1. Why can't I write foreach(i, el;
> > pathSplitter("foor/bar").enumerate)  ?
> > 2. Supposing I want to fix this problem, what do I add to the
> > struct? opApply?
>
> There was a stupid stupid error on my part because I wasn't import the range module.
>
> > 3. Why doesn't ranges infer the iteration method at compile time so that I don't need to write enumerate?
>
> This question is still valid.
> I think it would be saner to write
> foreach(idx, el; paths)
> instead of
> foreach(idx, el; paths.enumerate)

Perhaps, but foreach does not support that.

foreach(e; range)
{
    ...
}

is lowered to something like

for(auto __range = range; !__range.empty; __range.popFront())
{
    auto e = __range.front;
    ...
}

In order to support indices, it would need to also add a size_t that it incremented as it iterated the range, and the language doesn't support that.

It would be useful in many cases, and it would make sense for many ranges, but it arguably doesn't make sense for others. In particular, it would pose a problem for infinite ranges, and it's been argued before that for stuff like AAs where you're not really dealing with a linear list, it doesn't make sense (though that's debatable, since the range itself is linear even if it doesn't relate to indices into anything).

Ultimately, it's one of those things where it was trivial to solve with a library solution, so it wasn't added to the language. I don't know what the odds would be of a DIP which adds it to the language being accepted, but I suspect that it would be rejected on the grounds that it's already solved with a library solution. Over time, Walter and Andrei have increasingly favored library solutions over language solutions when a library solution will do the job, though certainly sometimes it's debatable as to whether a language solution would be better.

- Jonathan M Davis

February 07, 2018
On Wednesday, 7 February 2018 at 01:45:27 UTC, Jonathan M Davis wrote:
> Perhaps, but foreach does not support that.
>
> foreach(e; range)
> {
>     ...
> }
>
> is lowered to something like
>
> for(auto __range = range; !__range.empty; __range.popFront())
> {
>     auto e = __range.front;
>     ...
> }


Fun fact: an actual lowering from the compiler:

Result __r39 = iota(2).opSlice();
for (; !__r39.empty(); __r39.popFront())
{
	int a = __r39.front();
}


https://run.dlang.io/is/QihjQi

(sorry for being slightly off-topic, but it's always interesting for me to check whether our assumptions for of the inner-workings of the compiler are true ...)