www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - foreach/iota countdown

reply "simendsjo" <simendsjo gmail.com> writes:
Should the following two uses be a compile-time error?
   foreach(i; 10 .. 0) // Never executes

   foreach(i; iota(10, 0)) // .. neither does this

I would like the second to either be a compile-time error or 
automagically use a negative step.

So we need to use a negative step in iota() or use a for loop
   foreach(i; iota(10, 0, -1)) // as expected
Feb 17 2014
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/17/2014 08:22 PM, simendsjo wrote:
 Should the following two uses be a compile-time error?
    foreach(i; 10 .. 0) // Never executes

    foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
    foreach(i; iota(10, 0, -1)) // as expected
The parameters can be runtime values. Auto-magically using a negative step would hence be a bad idea.
Feb 17 2014
parent reply "simendsjo" <simendsjo gmail.com> writes:
On Monday, 17 February 2014 at 19:30:38 UTC, Timon Gehr wrote:
 On 02/17/2014 08:22 PM, simendsjo wrote:
 Should the following two uses be a compile-time error?
   foreach(i; 10 .. 0) // Never executes

   foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
   foreach(i; iota(10, 0, -1)) // as expected
The parameters can be runtime values. Auto-magically using a negative step would hence be a bad idea.
Why would it be a bad idea? And I don't see where the runtime aspect comes in. There would be a very small setup performance hit when using runtime variables for choosing the step direction.
Feb 17 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/17/2014 08:33 PM, simendsjo wrote:
 On Monday, 17 February 2014 at 19:30:38 UTC, Timon Gehr wrote:
 On 02/17/2014 08:22 PM, simendsjo wrote:
 Should the following two uses be a compile-time error?
   foreach(i; 10 .. 0) // Never executes

   foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
   foreach(i; iota(10, 0, -1)) // as expected
The parameters can be runtime values. Auto-magically using a negative step would hence be a bad idea.
Why would it be a bad idea?
The step direction shouldn't randomly change.
 And I don't see where the runtime aspect comes in.
It was just to illustrate the issue more clearly. Eg. it means one and the same iota expression can sometimes iterate in one direction and in the other direction at other times. That's simply not useful behaviour.
 There would be a very small setup performance hit when using runtime
 variables for choosing the step direction.
Feb 17 2014
parent reply "simendsjo" <simendsjo gmail.com> writes:
On Monday, 17 February 2014 at 20:03:32 UTC, Timon Gehr wrote:
 On 02/17/2014 08:33 PM, simendsjo wrote:
 On Monday, 17 February 2014 at 19:30:38 UTC, Timon Gehr wrote:
 On 02/17/2014 08:22 PM, simendsjo wrote:
 Should the following two uses be a compile-time error?
  foreach(i; 10 .. 0) // Never executes

  foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
  foreach(i; iota(10, 0, -1)) // as expected
The parameters can be runtime values. Auto-magically using a negative step would hence be a bad idea.
Why would it be a bad idea?
The step direction shouldn't randomly change.
I wouldn't call it randomly. In that case you should call it randomly that it suddenly doesn't run once you try to step downward.
 And I don't see where the runtime aspect comes in.
It was just to illustrate the issue more clearly. Eg. it means one and the same iota expression can sometimes iterate in one direction and in the other direction at other times. That's simply not useful behaviour.
I'm not sure what I find more confusing. Ok if it's a deliberate choice never to change the step direction, but is it deliberate that it's not an error to have a greater lower bound than upper bound? Or is this just the way it happened to be implemented?
Feb 17 2014
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/17/2014 09:21 PM, simendsjo wrote:
 On Monday, 17 February 2014 at 20:03:32 UTC, Timon Gehr wrote:
 ...

 It was just to illustrate the issue more clearly. Eg. it means one and
 the same iota expression can sometimes iterate in one direction and in
 the other direction at other times. That's simply not useful behaviour.
I'm not sure what I find more confusing. Ok if it's a deliberate choice never to change the step direction, but is it deliberate that it's not an error to have a greater lower bound than upper bound? Or is this just the way it happened to be implemented?
That's deliberate. I don't really understand how it is confusing. To draw an analogy, given (low ∈ ℕ) and (high ∈ ℕ), { x ∈ ℕ | low ≤ x ∧ x < high } is just the empty set if low > high. It is not illegal or unusual.
Feb 17 2014
parent reply "simendsjo" <simendsjo gmail.com> writes:
On Monday, 17 February 2014 at 21:06:50 UTC, Timon Gehr wrote:
 On 02/17/2014 09:21 PM, simendsjo wrote:
 On Monday, 17 February 2014 at 20:03:32 UTC, Timon Gehr wrote:
 ...

 It was just to illustrate the issue more clearly. Eg. it 
 means one and
 the same iota expression can sometimes iterate in one 
 direction and in
 the other direction at other times. That's simply not useful 
 behaviour.
I'm not sure what I find more confusing. Ok if it's a deliberate choice never to change the step direction, but is it deliberate that it's not an error to have a greater lower bound than upper bound? Or is this just the way it happened to be implemented?
That's deliberate. I don't really understand how it is confusing. To draw an analogy, given (low ∈ ℕ) and (high ∈ ℕ), { x ∈ ℕ | low ≤ x ∧ x < high } is just the empty set if low > high. It is not illegal or unusual.
Ok, I yield. I just happened to write foreach(i; 10 .. 0) and was suprised that it didn't give any warnings or errors. But I still somewhat stand by my point: Dead code is illegal in D, and this is code that will never run, hence dead code.
Feb 17 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/17/2014 10:12 PM, simendsjo wrote:
 Ok, I yield. I just happened to write
    foreach(i; 10 .. 0)
 and was suprised that it didn't give any warnings or errors.

 But I still somewhat stand by my point: Dead code is illegal in D,
(No it is not. Some forms of dead code are detected by DMD, but only with the -w switch.)
 and this is code that will never run, hence dead code.
The following does not give any warnings or errors either: void main(){ for(int i=10;i<0;i++){ } }
Feb 17 2014
prev sibling parent "Francesco Cattoglio" <francesco.cattoglio gmail.com> writes:
On Monday, 17 February 2014 at 20:21:30 UTC, simendsjo wrote:
 I wouldn't call it randomly. In that case you should call it 
 randomly that it suddenly doesn't run once you try to step 
 downward.
I didn't had time to work more on the iota. Perhaps after 2.065 is out I can resume working on that, but I'm really short of time right now. Allowing iota to iterate downward might become a horrible idea when we finally extend iota to other non-numeric types. The big issue is that types that define both opUnary!"++" and opUnary!"--" would behave in a completely different way from types that only define opUnary!"++". from http://forum.dlang.org/thread/mwwznnobgecnwermrndq forum.dlang.org example: type T implements ++t and --t; type P only implements ++p; t1 < t2 => iota(t2, t1) has a way to compute a non-empty range; p1 < p2 => iota(p2, p1) can do nothing but return an empty range; This really looks like a minefield to me.
Feb 17 2014
prev sibling next sibling parent "Mengu" <mengukagan gmail.com> writes:
On Monday, 17 February 2014 at 19:22:38 UTC, simendsjo wrote:
 Should the following two uses be a compile-time error?
   foreach(i; 10 .. 0) // Never executes

   foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or 
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
   foreach(i; iota(10, 0, -1)) // as expected
Ruby and Groovy has this feature. I'd support this.
Feb 17 2014
prev sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Monday, 17 February 2014 at 19:22:38 UTC, simendsjo wrote:
 Should the following two uses be a compile-time error?
   foreach(i; 10 .. 0) // Never executes

   foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or 
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
   foreach(i; iota(10, 0, -1)) // as expected
I just added this check to DScanner: ------------- import std.stdio; void main(string[] args) { auto x = args[3 .. 2]; foreach (i; 20 .. 10) { } } ------------- /home/alaran/tmp/test.d(5:16)[warn]: 3 is larger than 2. This slice is likely incorrect. /home/alaran/tmp/test.d(6:22)[warn]: 20 is larger than 10. Did you mean to use 'foreach_reverse( ... ; 10 .. 20)'?
Feb 17 2014
parent reply "Sergei Nosov" <sergei.nosov gmail.com> writes:
On Tuesday, 18 February 2014 at 05:21:24 UTC, Brian Schott wrote:
 On Monday, 17 February 2014 at 19:22:38 UTC, simendsjo wrote:
 Should the following two uses be a compile-time error?
  foreach(i; 10 .. 0) // Never executes

  foreach(i; iota(10, 0)) // .. neither does this

 I would like the second to either be a compile-time error or 
 automagically use a negative step.

 So we need to use a negative step in iota() or use a for loop
  foreach(i; iota(10, 0, -1)) // as expected
I just added this check to DScanner: ------------- import std.stdio; void main(string[] args) { auto x = args[3 .. 2]; foreach (i; 20 .. 10) { } } ------------- /home/alaran/tmp/test.d(5:16)[warn]: 3 is larger than 2. This slice is likely incorrect. /home/alaran/tmp/test.d(6:22)[warn]: 20 is larger than 10. Did you mean to use 'foreach_reverse( ... ; 10 .. 20)'?
Isn't foreach_reverse being deprecated?
Feb 18 2014
next sibling parent "Ivan Kazmenko" <gassa mail.ru> writes:
 /home/alaran/tmp/test.d(5:16)[warn]: 3 is larger than 2. This 
 slice is likely incorrect.
 /home/alaran/tmp/test.d(6:22)[warn]: 20 is larger than 10. Did 
 you mean to use 'foreach_reverse( ... ; 10 .. 20)'?
Isn't foreach_reverse being deprecated?
Oh. If so, what would be the right way to iterate backwards? The usual "for (*;*;*)" is too repetitive and error-prone: nothing is going to catch some "for (int i = 19; i >= 10; j--)" errors or the like. Using ranges, such as iota and retro, currently results in a *massive* slowdown for DMD. As a crude proof for the last statement, below are my local timings for DMD 2.064.2 on Win32 using "dmd -O -release -inline -noboundscheck" to compile. Example 1 (0.38 sec): void main () {foreach (i; 0..1_000_000_000) {}} Example 2 (0.39 sec): void main () {for (int i = 0; i < 1_000_000_000; i++) {}} Example 3 (2.03 sec): import std.range; void main () {foreach (i; iota (1_000_000_000)) {}} Unless simple things like example 3 run on par with the first two, foreach on ranges - or, in that regard, UFCS functional-style range chains without even a foreach - are just plain unacceptable in bottlenecks. LDC is able to handle simple cases like this, but introducing a compiler dependency just because of this? That would also be unfortunate. Ivan Kazmenko.
Feb 18 2014
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Sergei Nosov:

 Isn't foreach_reverse being deprecated?
The idea was discussed a little, but it's not deprecated, and probably it will not be deprecated. Bye, bearophile
Feb 18 2014