www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - foreach/opApply

reply Steve Teale <steve.teale britseyeview.com> writes:
foreach/opApply

Would it be a) true, and b) helpful if the documentation said something like:

The body of the apply function iterates over the elements it aggregates,
passing them each to the dg function, an implementation of which is provided by
the compiler for each opApply overload it encounters. If the dg returns 0, then
foreach goes on to the next element. If the dg returns a nonzero value, as it
will if, for example, a break or goto statement is executed in the loop, then
apply must cease iterating and return that value. Otherwise, after iterating
across all the elements, apply will return 0. 

The class need not contain an aggregate. The values iterated can be calculated
in opApply from other class members, though there should be a corresponding
class member  because of the ref in dg. The following example should make the
operation of foreach/opApply clear:

import std.stdio;

class Foo
{
    uint orig;
    uint cur;

    this(uint n) { orig = n; cur = n; }

    int opApply(int delegate(ref uint) dg)
    {
       writefln("enter opApply");
       int result = 0;

	    for (int i = 0; i < 50; i++)
	    {
	       result = dg(cur);
          writefln("Result %d", result);
	       if (result)
          {
             writefln(i);
             cur = orig;
		       break;
          }
          cur += cur*3;
	    }
       writefln("leave opApply");
	    return result;
    }
}

void main()
{
   Foo foo = new Foo(3);
   foreach(uint u; foo)
   {
      writefln(u);
      if (u > 200) goto L1;
   }
L1:
   foreach(uint u; foo)
   {
      writefln(u);
      if (u > 10000) break;

   }
   foreach(uint u; foo)
   {
      writefln(u);
      if (u > 10000) break;
      // The delegate takes a ref uint
      u = 0;
      writefln(u);

   }
}
Mar 19 2009
next sibling parent reply BCS <none anon.com> writes:
Hello Steve,

 foreach/opApply
 
 Would it be a) true, and b) helpful if the documentation said
 something like:
 
 The body of the apply function iterates over the elements it
 aggregates, passing them each to the dg function, 

 an implementation of
 which is provided by the compiler for each opApply overload it
 encounters.

I'm not shure that bit is correct. I'm not shure what you are saying.
 If the dg returns 0, then foreach goes on to the next
 element. If the dg returns a nonzero value, as it will if, for
 example, a break or goto statement is executed in the loop, then apply
 must cease iterating and return that value. Otherwise, after iterating
 across all the elements, apply will return 0.
 
 The class need not contain an aggregate. The values iterated can be
 calculated in opApply from other class members, though there should be
 a corresponding class member  because of the ref in dg. The following
 example should make the operation of foreach/opApply clear:
 
 import std.stdio;
 
 class Foo
 {
 uint orig;
 uint cur;
 this(uint n) { orig = n; cur = n; }
 
 int opApply(int delegate(ref uint) dg)
 {
 writefln("enter opApply");
 int result = 0;
 for (int i = 0; i < 50; i++)
 {
 result = dg(cur);
 writefln("Result %d", result);
 if (result)
 {
 writefln(i);
 cur = orig;
 break;
 }
 cur += cur*3;
 }
 writefln("leave opApply");
 return result;
 }
 }
 void main()
 {
 Foo foo = new Foo(3);
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 200) goto L1;
 }
 L1:
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 10000) break;
 }
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 10000) break;
 // The delegate takes a ref uint
 u = 0;
 writefln(u);
 }
 }

Mar 19 2009
parent reply Steve Teale <steve.teale britseyeview.com> writes:
BCS Wrote:

 Hello Steve,
 
 foreach/opApply
 
 Would it be a) true, and b) helpful if the documentation said
 something like:
 
 The body of the apply function iterates over the elements it
 aggregates, passing them each to the dg function, 

 an implementation of
 which is provided by the compiler for each opApply overload it
 encounters.

I'm not shure that bit is correct. I'm not shure what you are saying.
 If the dg returns 0, then foreach goes on to the next
 element. If the dg returns a nonzero value, as it will if, for
 example, a break or goto statement is executed in the loop, then apply
 must cease iterating and return that value. Otherwise, after iterating
 across all the elements, apply will return 0.
 
 The class need not contain an aggregate. The values iterated can be
 calculated in opApply from other class members, though there should be
 a corresponding class member  because of the ref in dg. The following
 example should make the operation of foreach/opApply clear:
 
 import std.stdio;
 
 class Foo
 {
 uint orig;
 uint cur;
 this(uint n) { orig = n; cur = n; }
 
 int opApply(int delegate(ref uint) dg)
 {
 writefln("enter opApply");
 int result = 0;
 for (int i = 0; i < 50; i++)
 {
 result = dg(cur);
 writefln("Result %d", result);
 if (result)
 {
 writefln(i);
 cur = orig;
 break;
 }
 cur += cur*3;
 }
 writefln("leave opApply");
 return result;
 }
 }
 void main()
 {
 Foo foo = new Foo(3);
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 200) goto L1;
 }
 L1:
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 10000) break;
 }
 foreach(uint u; foo)
 {
 writefln(u);
 if (u > 10000) break;
 // The delegate takes a ref uint
 u = 0;
 writefln(u);
 }
 }


Well, I'm not sure either, that's why I was asking. But I don't define the delegate, so I presume it must be done for me (as in how many C++ programmers does it take to change a light bulb). Otherwise what I'm saying seems to fit my test program. I'm just saying the documentation could be made more straightforward for beginners to use.
Mar 19 2009
parent BCS <ao pathlink.com> writes:
Reply to Steve,

 BCS Wrote:
 
 Hello Steve,
 
 an implementation of
 which is provided by the compiler for each opApply overload it
 encounters.

I'm not shure that bit is correct. I'm not shure what you are saying.

the delegate, so I presume it must be done for me (as in how many C++ programmers does it take to change a light bulb). Otherwise what I'm saying seems to fit my test program. I'm just saying the documentation could be made more straightforward for beginners to use.

It was a bit confusing if I'm remember the correct part. I think you have it correct. What I'm not sure on is the *overload* bit. What overloading are you referring to.
Mar 19 2009
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Steve Teale wrote:
 The class need not contain an aggregate. The values iterated can be calculated
in opApply from other class members, though there should be a corresponding
class member  because of the ref in dg.

It could correspond to a local variable instead. However, I'm curious about this: why is it that opApply must take a delegate with ref parameters? This doesn't make sense in many situations. I'm calculating values on the fly, and I can't go back if you decrement the index; the data I am passing is immutable (or at least in the text segment of the binary, which is protected as readonly and will segfault if you try writing to it). But I still need to pass by reference. So, why? It didn't always work like that.
Mar 19 2009