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");
    }
}
//====

Reply via email to