www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is there no range iteration with index by the language?

reply Q. Schroll <qs.il.paperinik gmail.com> writes:
Is there any particular reason why std.range : enumerate is a 
thing and

     foreach (i, e; range) { ... }

doesn't work from the get-go? I wouldn't have such an issue with 
it if static foreach would work with enumerate just fine. As far 
as I can tell,

     foreach (e; range) { ... }

is being lowered to

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

So why cant DMD rewrite

     foreach (i, e; range) { ... }

to

     for (auto _range = range, index = size_t(0); !_range.empty; 
_range.popFront, ++index)
     {
         size_t i = index;
         auto e = _range.front;
         ...
     }

Doesn't seem like a big deal, does it? I'm asking because I 
suspect there's an odd reason I have no idea and I whish to be 
educated.
Jun 09 2020
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jun 09, 2020 at 11:53:16PM +0000, Q. Schroll via Digitalmars-d-learn
wrote:
 Is there any particular reason why std.range : enumerate is a thing
 and
 
     foreach (i, e; range) { ... }
 
 doesn't work from the get-go?
[...] std.range.indexed is your friend. ;-) T -- Let's eat some disquits while we format the biskettes.
Jun 09 2020
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jun 09, 2020 at 05:03:55PM -0700, H. S. Teoh via Digitalmars-d-learn
wrote:
 On Tue, Jun 09, 2020 at 11:53:16PM +0000, Q. Schroll via Digitalmars-d-learn
wrote:
 Is there any particular reason why std.range : enumerate is a thing
 and
 
     foreach (i, e; range) { ... }
 
 doesn't work from the get-go?
[...] std.range.indexed is your friend. ;-)
[...] Aaah, that function doesn't do what I thought it did. Sorry!! :-( What you want is std.range.enumerate. But you already knew that. T -- EMACS = Extremely Massive And Cumbersome System
Jun 09 2020
prev sibling next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 9 June 2020 at 23:53:16 UTC, Q. Schroll wrote:
 Is there any particular reason why std.range : enumerate is a 
 thing and

 [...]
I don't think there is any particular reason. Other than that might shadow an opApply. And C++ iterators didn't have it.
Jun 09 2020
prev sibling next sibling parent reply Seb <seb wilzba.ch> writes:
On Tuesday, 9 June 2020 at 23:53:16 UTC, Q. Schroll wrote:
 Is there any particular reason why std.range : enumerate is a 
 thing and

     foreach (i, e; range) { ... }

 doesn't work from the get-go? I wouldn't have such an issue 
 with it if static foreach would work with enumerate just fine. 
 As far as I can tell,

     foreach (e; range) { ... }

 is being lowered to

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

 So why cant DMD rewrite

     foreach (i, e; range) { ... }

 to

     for (auto _range = range, index = size_t(0); !_range.empty; 
 _range.popFront, ++index)
     {
         size_t i = index;
         auto e = _range.front;
         ...
     }

 Doesn't seem like a big deal, does it? I'm asking because I 
 suspect there's an odd reason I have no idea and I whish to be 
 educated.
It's a bit more complicated though as you need to avoid subtle breakage with ranges that return tuples that are auto-expanded like e.g. `foreach (k,v; myDict)`. So IIRC the main reason why D's foreach magic isn't doing this is that it was argued that this problem is not significant enough to be worth fixing as there's enumerate and "there's bigger fish to fry". Anyhow, I would be highly in favor of DMD doing this. It's one of those many things that I have on my list for D3 or a D fork.
Jun 09 2020
next sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Wednesday, 10 June 2020 at 00:53:30 UTC, Seb wrote:
 It's a bit more complicated though as you need to avoid subtle 
 breakage with ranges that return tuples that are auto-expanded 
 like e.g. `foreach (k,v; myDict)`.
Okay, I can accept that. It's a poor decision, but well, it is what it is.
 Anyhow, I would be highly in favor of DMD doing this. It's one 
 of those many things that I have on my list for D3 or a D fork.
Is there any "official" or at least public list for D3 suggestions? Many people here talk about it recently...
Jun 09 2020
parent Seb <seb wilzba.ch> writes:
On Wednesday, 10 June 2020 at 01:35:32 UTC, Q. Schroll wrote:
 On Wednesday, 10 June 2020 at 00:53:30 UTC, Seb wrote:
 It's a bit more complicated though as you need to avoid subtle 
 breakage with ranges that return tuples that are auto-expanded 
 like e.g. `foreach (k,v; myDict)`.
Okay, I can accept that. It's a poor decision, but well, it is what it is.
 Anyhow, I would be highly in favor of DMD doing this. It's one 
 of those many things that I have on my list for D3 or a D fork.
Is there any "official" or at least public list for D3 suggestions? Many people here talk about it recently...
No, there's nothing "official" not public lists yet. However, there are two good related wiki pages: https://wiki.dlang.org/Language_issues https://wiki.dlang.org/Language_design_discussions
Jun 09 2020
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 10 June 2020 at 00:53:30 UTC, Seb wrote:
 [snip]

 Anyhow, I would be highly in favor of DMD doing this. It's one 
 of those many things that I have on my list for D3 or a D fork.
Chapel supports zippered iteration [1]. From the discussion here, it sounds very much like the implementation is similar to what D does with tuples. It probably would be pretty trivial with first class tuples. [1] https://chapel-lang.org/docs/language/spec/statements.html#zipper-iteration
Jun 10 2020
prev sibling next sibling parent Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 9 June 2020 at 23:53:16 UTC, Q. Schroll wrote:
 Is there any particular reason why std.range : enumerate is a 
 thing
Someone already mentioned dictionary. Consider that most ranges don't actually have an index. In this case you aren't actually asking to add indexes, but a count of iteration. For those ranges which do have indexing, what if the range is iterating from a location in the middle. Now you have an iteration count but not the true index. `enumerate` allows for specifying a starting number but this still isn't sufficient since a filter could easily jump to any index. Now none of this may come as a surprise to you, but having an iteration counter and an array index using the same api does open the door for confusion.
Jun 10 2020
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/9/20 7:53 PM, Q. Schroll wrote:
 Is there any particular reason why std.range : enumerate is a thing and
 
      foreach (i, e; range) { ... }
 
 doesn't work from the get-go? I wouldn't have such an issue with it if 
 static foreach would work with enumerate just fine.
What is the use case for static foreach and enumerate? My biggest problem with enumerate is that you can't bind the tuple to parameters for something like map: arr.enumerate.map!((idx, val) => ...) doesn't work. Instead you have to do: arr.enumerate.map!((tup) => ...) And use tup[0] and tup[1]. -Steve
Jun 10 2020
parent Dukc <ajieskola gmail.com> writes:
On Wednesday, 10 June 2020 at 15:34:57 UTC, Steven Schveighoffer 
wrote:
 My biggest problem with enumerate is that you can't bind the 
 tuple to parameters for something like map:

 arr.enumerate.map!((idx, val) => ...)

 doesn't work. Instead you have to do:

 arr.enumerate.map!((tup) => ...)

 And use tup[0] and tup[1].

 -Steve
``` alias tupArg(alias func) = x => func(x.expand); arr.enumerate.map!(tupArg!((idx, val) => ...)) ``` Somewhat heavy on syntax, but better than `tup[0]` or `tup[1]` IMO.
Jun 10 2020