Thread overview
[Issue 4112] New: Stride in foreach ranges
Feb 09, 2011
Denis Derman
Feb 09, 2011
Denis Derman
April 21, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=4112

           Summary: Stride in foreach ranges
           Product: D
           Version: future
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: bearophile_hugs@eml.cc


--- Comment #0 from bearophile_hugs@eml.cc 2010-04-21 14:09:48 PDT ---
In D2 the range syntax of foreach is useful because it helps state the iteration variable one time only instead of tree, it's cleaner and less bug-prone than the normal for syntax, and it's useful in many situations because many for loops are just over a numeric range (so the normal for syntax can be left for more complex situations).

But beside natural series, for loops over arithmetic ranges too are common. Currently in D2 this requires a normal for syntax:

for (int i = 0; i < 100; i += 2) {}

My experience with Python tells me that an optional stride can be useful here. This is a possible syntax (the colon is useful to visually tell apart the third value):

foreach (i; 0 .. 100 : 2) {}

(To keep things simpler, it can even be acceptable for the stride value to be a value known at compile-time).

See also bug 4111.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 09, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=4112


Denis Derman <denis.spir@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |denis.spir@gmail.com


--- Comment #1 from Denis Derman <denis.spir@gmail.com> 2011-02-09 05:41:42 PST ---
I'm unsure whether this is a good thing. The issue is, for me, this feature
would only apply to numeric intervals (probably even only on integral ones).
While the notion of "by-step iteration" is completely general; I guess simply
orthogonal to sequence / iteration / range.
Thus, I would prefere a range factory like

    auto byStep (R) (int step) if (...)

typical use case:

    foreach (n ; iota(1..1000).byStep(3)) {...}

or better (see http://d.puremagic.com/issues/show_bug.cgi?id=5395)
    foreach (n ; (1..1000).byStep(3) {...}

What do you think?

Negative step meaning backwards? So that we get reverse for free... An issue is, if this is not the case but negative step is intepreted literally, we get a very weird semantics compared to apparent meaning.

Example for the simplest case of reverse iteration. Should iterating backwards
on 0..4 (meaning 3->2->1->0) be written (more direct):
    foreach (n ; (0..4).byStep(-1))
(translation in the case of indices:)
    foreach (i ; (0..a.length).byStep(-1))

or instead (more logical but imo completely unintuitive and difficult):
    foreach (n ; (3..-1).byStep(-1))
(translation in the case of indices:)
    foreach (i ; (a.length-1..-1).byStep(-1))

By the way, this issue applies to your proposal as well: what does 1..3:-2
Actually mean?
Finally, if ever we had a step syntax for i..j, I would prefere '/' than ':',
read as "by":
    foreach (; i..j:k
--> traverse the interval i..j 'by' (steps of) k.


Denis

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 09, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=4112



--- Comment #2 from Denis Derman <denis.spir@gmail.com> 2011-02-09 05:44:17 PST ---
(Grrr! How can we edit our own posts? Could not find it.)

That was supposed to be:

Finally, if ever we had a step syntax for i..j, I would prefere '/' than ':',
read as "by":
    foreach (n ; i..j/k)
--> traverse the interval i..j 'by' (steps of) k.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 09, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=4112


Andrei Alexandrescu <andrei@metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrei@metalanguage.com


--- Comment #3 from Andrei Alexandrescu <andrei@metalanguage.com> 2011-02-09 06:11:30 PST ---
(In reply to comment #2)
> (Grrr! How can we edit our own posts? Could not find it.)
> 
> That was supposed to be:
> 
> Finally, if ever we had a step syntax for i..j, I would prefere '/' than ':',
> read as "by":
>     foreach (n ; i..j/k)
> --> traverse the interval i..j 'by' (steps of) k.

That's traverse the interval i..j/k.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 09, 2011
http://d.puremagic.com/issues/show_bug.cgi?id=4112



--- Comment #4 from bearophile_hugs@eml.cc 2011-02-09 10:17:09 PST ---
(In reply to comment #1)
> or better (see http://d.puremagic.com/issues/show_bug.cgi?id=5395)
>     foreach (n ; (1..1000).byStep(3) {...}
> 
> What do you think?

Your syntax is too much wordy for something so common as this. There are too many parentheses too, that increase syntax noise and cause errors similar to your one, you have forgotten a closing ).


> By the way, this issue applies to your proposal as well: what does 1..3:-2 Actually mean?

In Python it gives an empty range. The semantics of a negative stride is well founded in Python:

>>> range(1, 3, -2)
[]


> Finally, if ever we had a step syntax for i..j, I would prefere '/' than ':',
> read as "by":
>     foreach (; i..j:k
> --> traverse the interval i..j 'by' (steps of) k.

The / syntax means something different already:

import std.stdio;
void main() {
    int i = 10;
    int j = 100;
    int k = 5;
    foreach (x; i .. j / k)
        writeln(x);
}

==>
10
11
12
13
14
15
16
17
18
19

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------