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