www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Switch constants

reply bearophile <bearophileHUGS lycos.com> writes:
In a not-ranged cases body, like in the program below (that doesn't compile),
the switch variable is a compile-time constant, so why doesn't the compile see
x as constant there?


template Foo(uint x) {
    static if (x <= 1)
        enum Foo = 1;
    else
        enum Foo = x * Foo!(x - 1);
}

int bar(uint x) {
    switch (x) {
        case 0: return Foo!x;
        case 1: return Foo!x;
        case 2: return Foo!x;
        case 3: return Foo!x;
        case 4: return Foo!x;
        default: return -1;
    }
}

void main() {
    assert(bar(4) == 24);
}


That code works if I replace lines like:
case 2: return Foo!x;

With:
case 2: return Foo!2;

But when the code isn't DRY bugs may happen...
(There are ten different better ways to write that program, but this is not the
point).

Bye,
bearophile
Nov 13 2010
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.11.2010 1:21, bearophile wrote:
 In a not-ranged cases body, like in the program below (that doesn't compile),
the switch variable is a compile-time constant, so why doesn't the compile see
x as constant there?

In essence "case x:" is nothing but a glorified local label.
 template Foo(uint x) {
      static if (x<= 1)
          enum Foo = 1;
      else
          enum Foo = x * Foo!(x - 1);
 }

 int bar(uint x) {
      switch (x) {
          case 0: return Foo!x;
          case 1: return Foo!x;
          case 2: return Foo!x;
          case 3: return Foo!x;
          case 4: return Foo!x;
          default: return -1;
      }
 }

 void main() {
      assert(bar(4) == 24);
 }


 That code works if I replace lines like:
 case 2: return Foo!x;

 With:
 case 2: return Foo!2;

 But when the code isn't DRY bugs may happen...
 (There are ten different better ways to write that program, but this is not
the point).

 Bye,
 bearophile

-- Dmitry Olshansky
Nov 13 2010
prev sibling next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:ibn320$2ucs$1 digitalmars.com...
 In a not-ranged cases body, like in the program below (that doesn't 
 compile), the switch variable is a compile-time constant, so why doesn't 
 the compile see x as constant there?

In switch statements, you can do stuff like: switch(x) { case 0: case 1: // what is x here? break; } switch(x) { case 0: break; // what is x here? case 1: goto case 0: } goto label1; switch(x) { case 0: label1: break; // what is x here? } switch(x) { case 0: x = y; break; // what is x here? } As far as I know, NONE of the constructs in d allow you to treat a run-time variable as if it was compile-time constant. I doubt this would be possible without flow analysis. You can however do something like this (if you must) template Foo(uint x) { static if (x <= 1) enum Foo = 1; else enum Foo = x * Foo!(x - 1); } int getv(int x) { switch(x) { foreach(i; TypeTuple!(0, 1, 2, 3, 4, 5, 6)) { case i: return Foo!i; } } assert(0); } where the switch expands out to switch(x) { case 0: return Foo!0; case 1: return Foo!1; case 2: return Foo!2; case 3: return Foo!3; case 4: return Foo!4; case 5: return Foo!5; case 6: return Foo!6; } Is this DRY enough for you?
Nov 13 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Daniel Murphy:

 switch(x)
 {
 case 0:
    break; // what is x here?
 case 1:
    goto case 0:
 }
 etc

You are right. Thank you for all the answers. Bye, bearophile
Nov 13 2010
prev sibling next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
bearophile wrote:
 In a not-ranged cases body, like in the program below (that doesn't compile),
the switch variable is a compile-time constant, so why doesn't the compile see
x as constant there?
 
 
 template Foo(uint x) {
     static if (x <= 1)
         enum Foo = 1;
     else
         enum Foo = x * Foo!(x - 1);
 }
 
 int bar(uint x) {
     switch (x) {
         case 0: return Foo!x;
         case 1: return Foo!x;
         case 2: return Foo!x;
         case 3: return Foo!x;
         case 4: return Foo!x;
         default: return -1;
     }
 }
 
 void main() {
     assert(bar(4) == 24);
 }
 
 
 That code works if I replace lines like:
 case 2: return Foo!x;
 
 With:
 case 2: return Foo!2;
 
 But when the code isn't DRY bugs may happen...
 (There are ten different better ways to write that program, but this is not
the point).
 
 Bye,
 bearophile

I would say that while bar may be CTFE'd, it is nevertheless a function that can be called at runtime, in which case x may no longer be a compile-time constant. So there is little compiler can do except for refusing such code.
Nov 13 2010
prev sibling parent BCS <anon anon.com> writes:
Hello bearophile,

 In a not-ranged cases body, like in the program below (that doesn't
 compile), the switch variable is a compile-time constant, so why
 doesn't the compile see x as constant there?
 
 template Foo(uint x) {
 static if (x <= 1)
 enum Foo = 1;
 else
 enum Foo = x * Foo!(x - 1);
 }
 int bar(uint x) {
 switch (x) {
 case 0: return Foo!x;
 case 1: return Foo!x;
 case 2: return Foo!x;
 case 3: return Foo!x;
 case 4: return Foo!x;
 default: return -1;
 }
 }

If you want exactly that: switch(x) { foreach(X; Tuple!(0,1,2,3,4)) { case X: return Foo!X; } }
Nov 14 2010