www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Switch with dynamic case

reply Daniel Kozak <kozzi11 gmail.com> writes:
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?
Feb 02 2016
parent reply anonymous <anonymous example.com> writes:
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.
Feb 02 2016
parent Daniel Kozak <kozzi11 gmail.com> writes:
On Tuesday, 2 February 2016 at 15:01:57 UTC, anonymous wrote:
 On 02.02.2016 15:07, Daniel Kozak wrote:
 [...]
The key thing to understand is that the foreach is a "static" one. A static foreach is unrolled at compile-time. [...]
Thanks :), this is all I need to know
Feb 02 2016