A possible suggestion for the Foreach loop

monarch_dodra monarchdodra at gmail.com
Wed Aug 21 03:40:06 PDT 2013


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


More information about the Digitalmars-d mailing list