On Wednesday, 21 August 2013 at 10:40:10 UTC, monarch_dodra wrote:
On Wednesday, 21 August 2013 at 02:46:06 UTC, Dylan Knutson wrote:
Hello,

I'd like to open up discussion regarding allowing foreach loops which iterate over a tuple of types to exist outside of function bodies. I think this would allow for templating constants and unittests easier. Take, for instance, this hypothetical example:

----------------------------------------------------------------------
T foo(T)(ref T thing)
{
        thing++; return thing * 2;
}

foreach(Type; TupleType!(int, long, uint))
{
        unittest
        {
                Type tmp = 5;
                assert(foo(tmp) == 12);
        }
        
        unittest
        {
                Type tmp = 0;
                foo(tmp);
                assert(tmp == 1);
        }
}
----------------------------------------------------------------------

Without the ability to wrap all of the unittests in a template, one would have to wrap the bodies of each unittest in an individual foreach loop. This is not only repetitive and tedious, but error prone, as changing the types tested then requires the programmer to change *every* instance of the foreach(Type; TupleType).

A similar pattern already exists in Phobos, for testing all variants of strings (string, dstring, and wstring) and char types, as eco brought to my attention. After taking a look at some of the unittests that employ this pattern, I'm certain that code clarity and unittest quality could be improved by simply wrapping all of the individual unittests themselves in a foreach as described above.

Now, I'm certainly no D expert, but I can't think of any breakages this change might impose on the language itself. So, I'd like to hear what the benevolent overlords and community think of the idea.

This makes sense to me. After all, a static foreach no different in its result from a static if. Here is an example usecase:

//----
foreach(T)(TypeTuple!(float, double, real))
{
    void someFunction(T val)
    {some_body;}
}
//----

This, contrary to making someFunction a template, eagerly compiles someFunction. This makes it "ship-able" in a library.

Also, it avoid "over instantiations": More often than not, for example, a template will be instantiated with "double", but also "const double" and "immutable double".

It also avoids having to over-think the template restraints.

This is just one example, but I can *definitly* see it making sense in over ways.

========

Also, I find it strange that the above is not legal, but that this works:

//====
import std.stdio, std.typecons;

alias cases = TypeTuple!(2, 3, 4, 7, 8);

void main()
{
    int i = 7;
    switch(i)
    {
        //cases defined
        foreach (v; cases)
        {
            case v:
        }
        {
            writeln("match");
        }
        break;

        default:
            writeln("no match");
    }
}
//====


In a previous project I needed exactly this (I needed to declare various class data members based on a large tuple of types.) I ended up having to use string mixins, which was pretty unreadable. So I think it is a good idea, although I have no idea how viable/nonintrusive is it to add this to the language.

Reply via email to