www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How do I make my class iterable?

reply "Assembly" <jckj33 gmail.com> writes:
Does D has an equivalent to C#'s iterator 
(https://msdn.microsoft.com/en-us/library/65zzykke.aspx)? if so, 
where can I find it?

What I want is loop over a user-defined class/struct. In case of 
C#, I just implement the IEnumerable and the GetEnumerator() 
methods that's called by the foreach() construct together with 
the yield keyword I "feed" the loop until the moveNext() returns 
false (no next element). The think I've linked has some C# code 
example.

  Something like this:

struct MyStruct
{
    // proper methods/proeperties called by foreach() to iterate
    // over the array
    int[] myarr;
    int = 0;
    int getNext() { return myarr[i]; }
    bool hasNext() { return i == myarr.length; }
}

MyStruct s;
foreach(MyStruct x; s)
{

}

Is this possible?
Jun 22 2015
parent reply "q66" <daniel octaforge.org> writes:
On Monday, 22 June 2015 at 16:33:43 UTC, Assembly wrote:
 Does D has an equivalent to C#'s iterator 
 (https://msdn.microsoft.com/en-us/library/65zzykke.aspx)? if 
 so, where can I find it?

 What I want is loop over a user-defined class/struct. In case 
 of C#, I just implement the IEnumerable and the GetEnumerator() 
 methods that's called by the foreach() construct together with 
 the yield keyword I "feed" the loop until the moveNext() 
 returns false (no next element). The think I've linked has some 
 C# code example.

  Something like this:

 struct MyStruct
 {
    // proper methods/proeperties called by foreach() to iterate
    // over the array
    int[] myarr;
    int = 0;
    int getNext() { return myarr[i]; }
    bool hasNext() { return i == myarr.length; }
 }

 MyStruct s;
 foreach(MyStruct x; s)
 {

 }

 Is this possible?
use opApply.
Jun 22 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/22/2015 09:37 AM, q66 wrote:

 use opApply.
Yes. Additionally, an InputRange interface can be used: http://ddili.org/ders/d.en/foreach_opapply.html Ali
Jun 22 2015
parent reply "Assembly" <jckj33 gmail.com> writes:
On Monday, 22 June 2015 at 16:52:15 UTC, Ali Çehreli wrote:
 On 06/22/2015 09:37 AM, q66 wrote:

 use opApply.
Yes. Additionally, an InputRange interface can be used: http://ddili.org/ders/d.en/foreach_opapply.html Ali
I was reading exaclty this page that. I've had implmented this method/properties (I remembered how foreach() is translated to for() by the compiler using front/popFront() and such): T front() { return _app.data[index]; } T front(int index, T a) { return _app.data[index]; } void popFront() { index++; } and called like this: foreach(int i, MyType p; places) { but I get this error: Error: cannot infer argument types, expected 1 argument, not 2 to try solve that error I added the overload method: T front(int index, T a) but it didn't worked. How do I solve this?
Jun 22 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/22/15 1:03 PM, Assembly wrote:
 On Monday, 22 June 2015 at 16:52:15 UTC, Ali Çehreli wrote:
 On 06/22/2015 09:37 AM, q66 wrote:

 use opApply.
Yes. Additionally, an InputRange interface can be used: http://ddili.org/ders/d.en/foreach_opapply.html Ali
I was reading exaclty this page that. I've had implmented this method/properties (I remembered how foreach() is translated to for() by the compiler using front/popFront() and such): T front() { return _app.data[index]; } T front(int index, T a) { return _app.data[index]; } void popFront() { index++; } and called like this: foreach(int i, MyType p; places) { but I get this error: Error: cannot infer argument types, expected 1 argument, not 2 to try solve that error I added the overload method: T front(int index, T a) but it didn't worked. How do I solve this?
TBH, opApply is much better suited to classes. But in order to have multiple parameters with foreach by using a range, you must return a tuple: auto front() { import std.typecons: tuple; return tuple(index, _app.data[index]);} Note, do NOT do this on your class, you should be creating a range struct type, and return the range from opIndex() with no parameters. -Steve
Jun 22 2015
parent reply "Assembly" <jckj33 gmail.com> writes:
On Monday, 22 June 2015 at 17:09:16 UTC, Steven Schveighoffer 
wrote:
 On 6/22/15 1:03 PM, Assembly wrote:
 [...]
TBH, opApply is much better suited to classes. But in order to have multiple parameters with foreach by using a range, you must return a tuple: auto front() { import std.typecons: tuple; return tuple(index, _app.data[index]);} Note, do NOT do this on your class, you should be creating a range struct type, and return the range from opIndex() with no parameters. -Steve
I'm using this, thanks for all. Can someone clarify how does opApply() works? I assume it's called every iteration and as opApply() has a loop does it means the number of iteration ran actually is the ones from foreach() is 2*n where n is the number of elements in the array, is this right?
Jun 22 2015
parent reply "anonymous" <anonymous example.com> writes:
On Monday, 22 June 2015 at 18:44:22 UTC, Assembly wrote:
 I'm using this, thanks for all. Can someone clarify how does 
 opApply() works? I assume it's called every iteration and as 
 opApply() has a loop does it means the number of iteration ran 
 actually is the ones from foreach() is 2*n where n is the 
 number of elements in the array, is this right?
opApply is called only once. The body of the foreach is passed to opApply as a delegate. The opApply implementation runs the supplied foreach body, possibly in a loop. Every such call is an iteration of the foreach loop. With opApply this: foreach(x; iterable) {/* do something with x */} gets rewritten to this: iterable.opApply((x) {/* do something with x */});
Jun 22 2015
parent "Assembly" <jckj33 gmail.com> writes:
On Monday, 22 June 2015 at 20:34:00 UTC, anonymous wrote:
 On Monday, 22 June 2015 at 18:44:22 UTC, Assembly wrote:
 I'm using this, thanks for all. Can someone clarify how does 
 opApply() works? I assume it's called every iteration and as 
 opApply() has a loop does it means the number of iteration ran 
 actually is the ones from foreach() is 2*n where n is the 
 number of elements in the array, is this right?
opApply is called only once. The body of the foreach is passed to opApply as a delegate. The opApply implementation runs the supplied foreach body, possibly in a loop. Every such call is an iteration of the foreach loop. With opApply this: foreach(x; iterable) {/* do something with x */} gets rewritten to this: iterable.opApply((x) {/* do something with x */});
got it, thanks :)
Jun 22 2015
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/22/2015 10:03 AM, Assembly wrote:

 foreach(int i, MyType p; places) {

 but I get this error:

 Error: cannot infer argument types, expected 1 argument, not 2
Yeah, the loop counter is automatic only for slices. You can use 'enumerate' for other types: foreach (i, element; NumberRange(42, 47).enumerate) { // ... } That is taken from the same page: ;) http://ddili.org/ders/d.en/foreach_opapply.html#ix_foreach_opapply.loop%20counter Ali
Jun 22 2015
parent reply "Assembly" <jckj33 gmail.com> writes:
On Monday, 22 June 2015 at 18:07:36 UTC, Ali Çehreli wrote:
 On 06/22/2015 10:03 AM, Assembly wrote:

 foreach(int i, MyType p; places) {

 but I get this error:

 Error: cannot infer argument types, expected 1 argument, not 2
Yeah, the loop counter is automatic only for slices. You can use 'enumerate' for other types: foreach (i, element; NumberRange(42, 47).enumerate) { // ... } That is taken from the same page: ;) http://ddili.org/ders/d.en/foreach_opapply.html#ix_foreach_opapply.loop%20counter Ali
if my opApply() is defiend as the following: int opApply(int delegate(ref int, ref T) del) { int result; foreach(int i, T val; _app.data) { result = del(i, _app.data[i]); if(result) break; } return result; } and called like: foreach(int i, MyType p; places) { isn't i the loop counter?
Jun 22 2015
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/22/2015 11:48 AM, Assembly wrote:

 if my opApply() is defiend as the following:

 int opApply(int delegate(ref int, ref T) del)
      {
[...]
      }

 and called like:

 foreach(int i, MyType p; places) {

 isn't i the loop counter?
size_t is more natural but yes, that's it. Ali
Jun 22 2015