Thread overview
isIterable(T)
Apr 26, 2009
dsimcha
Apr 26, 2009
Denis Koroskin
Apr 26, 2009
dsimcha
Apr 26, 2009
bearophile
Apr 26, 2009
dsimcha
Apr 26, 2009
bearophile
Apr 26, 2009
dsimcha
This and ElemType are also in tools.base.
Apr 27, 2009
downs
April 26, 2009
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.
April 26, 2009
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;	
   }
}


April 26, 2009
== 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.
> // Not tested
> 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[])));
April 26, 2009
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
April 26, 2009
== 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)
> 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

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));
}
April 26, 2009
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
April 26, 2009
== 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.
> 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

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.
April 27, 2009
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 :)