www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - isIterable(T)

reply dsimcha <dsimcha yahoo.com> writes:
I've been thinking a little more about ranges, etc. and it would be nice to
have a template for isIterable(T) that simply tells whether an object can be
iterated over with foreach, without caring how this iteration works (ranges,
opApply, builtin array/AA).  I have some use cases where I'm writing very
generic functionality and all I need is the lowest common denominator that,
given an object T, the following will compile, and to know what type elem
would be:

foreach(elem; T.init) {}

This functionality does not require any of the more advanced features of
ranges, just iteration.  Is there any good way to write a template for this?
Since foreach is a statement, is(typeof()) and __traits(compiles) are out.
Apr 26 2009
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 26 Apr 2009 21:44:31 +0400, dsimcha <dsimcha yahoo.com> wrote:

 I've been thinking a little more about ranges, etc. and it would be nice  
 to
 have a template for isIterable(T) that simply tells whether an object  
 can be
 iterated over with foreach, without caring how this iteration works  
 (ranges,
 opApply, builtin array/AA).  I have some use cases where I'm writing very
 generic functionality and all I need is the lowest common denominator  
 that,
 given an object T, the following will compile, and to know what type elem
 would be:

 foreach(elem; T.init) {}

 This functionality does not require any of the more advanced features of
 ranges, just iteration.  Is there any good way to write a template for  
 this?
 Since foreach is a statement, is(typeof()) and __traits(compiles) are  
 out.

// Not tested template isIterable(T) { static if (is(typeof({foreach(elem; T.init) {}})) { const bool isIterable = true; } else { const bool isIterable = false; } }
Apr 26 2009
parent dsimcha <dsimcha yahoo.com> writes:
== Quote from Denis Koroskin (2korden gmail.com)'s article
 On Sun, 26 Apr 2009 21:44:31 +0400, dsimcha <dsimcha yahoo.com> wrote:
 I've been thinking a little more about ranges, etc. and it would be nice
 to
 have a template for isIterable(T) that simply tells whether an object
 can be
 iterated over with foreach, without caring how this iteration works
 (ranges,
 opApply, builtin array/AA).  I have some use cases where I'm writing very
 generic functionality and all I need is the lowest common denominator
 that,
 given an object T, the following will compile, and to know what type elem
 would be:

 foreach(elem; T.init) {}

 This functionality does not require any of the more advanced features of
 ranges, just iteration.  Is there any good way to write a template for
 this?
 Since foreach is a statement, is(typeof()) and __traits(compiles) are
 out.

template isIterable(T) { static if (is(typeof({foreach(elem; T.init) {}})) { const bool isIterable = true; } else { const bool isIterable = false; } }

Wow, IDK why I thought that wouldn't work. I must have made some minor syntactical error b/c I tried the same thing a few minutes ago, yet somehow yours works. Only thing is, you forgot a ) at the end. Also, enum is more efficient than const. Here's a tested version. template isIterable(T) { static if (is(typeof({foreach(elem; T.init) {}}))) { enum bool isIterable = true; } else { enum bool isIterable = false; } } import std.range; // For testing. struct Foo { // For testing opApply. // For testing. int opApply(int delegate(ref uint) dg) { assert(0); } } static assert(isIterable!(uint[])); static assert(!isIterable!(uint)); static assert(isIterable!(Foo)); static assert(isIterable!(uint[string])); static assert(isIterable!(Chain!(uint[], uint[])));
Apr 26 2009
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha Wrote:
 I've been thinking a little more about ranges, etc. and it would be nice to
 have a template for isIterable(T)

I agree. IsIterable is already inside my dlibs (as the xkeys/xvalues you talk about in another post of yours, but in the "func" module), into the "templates" module: http://www.fantascienza.net/leonardo/so/dlibs/templates.html I suggest you to take a good look at those dlibs, you will probably find stuff you are going to think tomorrow and the day after tomorrow. Bye, bearophile
Apr 26 2009
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 dsimcha Wrote:
 I've been thinking a little more about ranges, etc. and it would be nice to
 have a template for isIterable(T)

IsIterable is already inside my dlibs (as the xkeys/xvalues you talk about in

 http://www.fantascienza.net/leonardo/so/dlibs/templates.html
 I suggest you to take a good look at those dlibs, you will probably find stuff

 Bye,
 bearophile

Thanks. The other part of the question, which all of us seemed to neglected was how to get the type of elem. I just got that to work, too. import std.traits, std.range; template IterType(T) { alias ReturnType!( { foreach(elem; T.init) { return elem; } }) IterType; } unittest { struct Foo { // For testing opApply. // For testing. int opApply(int delegate(ref uint) dg) { assert(0); } } static assert(is(IterType!(uint[]) == uint)); static assert(is(IterType!(Foo) == uint)); static assert(is(IterType!(uint[string]) == uint)); static assert(is(IterType!(Chain!(uint[], uint[])) == uint)); }
Apr 26 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
 Thanks.  The other part of the question, which all of us seemed to neglected
was
 how to get the type of elem.

See BaseType and BaseType1 in my "templates" module (I think you are talking about BaseType1 here, later you will probably feel the need of BaseType too, so I avoid posting another post later). Bye, bearophile
Apr 26 2009
parent dsimcha <dsimcha yahoo.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 dsimcha:
 Thanks.  The other part of the question, which all of us seemed to neglected
was
 how to get the type of elem.


avoid posting another post later).
 Bye,
 bearophile

Thanks. I haven't looked at your dlibs much, mostly because they're supposed to be for D1, and all my code is in D2. I guess there are some good template code snippets that generalize to D2 in there, though.
Apr 26 2009
prev sibling parent downs <default_357-line yahoo.de> writes:
bearophile wrote:
 dsimcha Wrote:
 I've been thinking a little more about ranges, etc. and it would be nice to
 have a template for isIterable(T)

I agree. IsIterable is already inside my dlibs (as the xkeys/xvalues you talk about in another post of yours, but in the "func" module), into the "templates" module: http://www.fantascienza.net/leonardo/so/dlibs/templates.html I suggest you to take a good look at those dlibs, you will probably find stuff you are going to think tomorrow and the day after tomorrow. Bye, bearophile

See title :)
Apr 27 2009