Switch with dynamic case

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Feb 2 07:01:57 PST 2016


On 02.02.2016 15:07, Daniel Kozak wrote:
> import std.stdio;
> import std.typetuple : TypeTuple;
>
> alias cs = TypeTuple!(0, 1, 2, 3);
>
> void main(string[] argv)
> {
>      switch(argv.length)
>      {
>          default: writeln("Uknown number of args"); break;
>          foreach(c; cs)
>          {
>              case c: writefln("%s args", c);
>              break;
>          }
>      }
> }
>
> This works, but I dont know why or how, is there some documentation
> about this feature?

The key thing to understand is that the foreach is a "static" one. A 
static foreach is unrolled at compile-time.

So that switch code is replaced at compile time with this, almost:

----
     switch(argv.length)
     {
         default: writeln("Uknown number of args"); break;

         case 0: writefln("%s args", 0);
         break;

         case 1: writefln("%s args", 1);
         break;

         case 2: writefln("%s args", 0);
         break;
     }
----

"But", I hear you ask, "it breaks when I put the default at the bottom. 
What's up with that?". Yeah, that's a bit weird/buggy.

The problem is with the break statement. It applies to the foreach, not 
to the switch. And while the foreach is unrolled at compile-time, the 
break is evaluated at run-time. The generated code really looks more 
like this:

----
     switch(argv.length)
     {
         default: writeln("Uknown number of args"); break;

         /* start of unrolled foreach */
         case 0: writefln("%s args", 0);
         goto behind_foreach;

         case 1: writefln("%s args", 1);
         goto behind_foreach;

         case 2: writefln("%s args", 0);
         goto behind_foreach;
         /* end of unrolled foreach */
         behind_foreach:
     }
----

So, the breaks skip past the other cases that were created by the 
foreach, but they don't actually break out of the switch.

There are at least two open issues related to this:

https://issues.dlang.org/show_bug.cgi?id=14887
https://issues.dlang.org/show_bug.cgi?id=7835

Everything works fine when breaking the switch with a label:

----
     sw: switch(argv.length)
     {
         foreach(c; cs)
         {
             case c: writefln("%s args", c);
             break sw;
         }
         default: writeln("Uknown number of args"); break;
     }
----

Unfortunately, the spec is rather quiet about static foreach. And you 
won't actually find the term "static foreach". The only thing I could 
find is a little "Foreach over Tuples" section on 
<https://dlang.org/spec/statement.html>, which doesn't tell a lot.


More information about the Digitalmars-d-learn mailing list