4

The following extract of code is failing to compile resulting in not code paths return a value. Both types Test1StandardChargeCalculator and Test2StandardChargeCalculator are derived from the return type.

I know how to fix this, but my question is why should I have to? A bool is a value type - hence can only represent true or false, both of which are catered for in this snippet. So why the failed compilation?

internal StandardChargeCalculator Create()
{
      bool value = true;

      switch (value)
      {
          case true:
              return new Test1StandardChargeCalculator();
          case false:
              return new Test2StandardChargeCalculator();
      }
} //not all code paths return a value
m.edmondson
  • 30,382
  • 27
  • 123
  • 206
  • Like I said I know *how* to fix this but *why* should I have to? – m.edmondson Mar 30 '12 at 08:52
  • 8
    Are you realy using switch for true/false checking? – Piotr Auguscik Mar 30 '12 at 08:52
  • @PiotrAuguscik - That's not the point of the question – m.edmondson Mar 30 '12 at 08:52
  • 1
    duplicate? http://stackoverflow.com/questions/1098644/switch-statement-without-default-when-dealing-with-enumerations – bobwah Mar 30 '12 at 08:53
  • @m.edmondson - switch doesn't know whether you want to return a value. – KV Prajapati Mar 30 '12 at 08:53
  • Case statements always complain if there are no breaks after each case. – willDaBeast Mar 30 '12 at 08:55
  • 1
    I think for boolean this is an interesting question since the halting problem doesn't apply in the specialized case. My guess: It would be inconsistent if switch works for some, but not all cases (since said halting problem cannot be solved for the general cases) and thus the compiler developers chose this behavior, since switching on a bool isn't really a big use case. – Michael Stum Mar 30 '12 at 08:56
  • 3
    @willDaBeast case statements don't need a break if the block returns or throws because that prevents the fall-through already. – Michael Stum Mar 30 '12 at 08:57
  • Would anyone cry if swith on bool wouldn't compile at all? I'd sure rather see switch on Types... – Jacek Gorgoń Mar 30 '12 at 09:18
  • FWIW you get the same error with a two-value enum `enum MyBoolean {TRUE, FALSE};` I'd be surprised if one of these worked and the other didn't. – Rup Mar 30 '12 at 10:06
  • 1
    Oded's answer is correct; I would just add that I wrote an article about this case, and three other interesting odd behaviours of the switch statement, back in 2009. You can read it here: http://blogs.msdn.com/b/ericlippert/archive/2009/08/13/four-switch-oddities.aspx – Eric Lippert Mar 30 '12 at 18:10
  • @Rup enums always have as many valid values as their underlying type. For example, `MyBoolean x = (MyBoolean)42;` will compile, and run, and store the value 42 in the variable x. You can't do anything similar with a boolean unless you get into unsafe code and bit twiddling. – phoog Apr 02 '12 at 17:08
  • @phoog Sure - but it seemed a sensible thing to try in the same vein so I thought I'd report the data point. That said, I thought the default underlying type was restricted to the number of bits necessary to store all values, but I'm probably getting confused with something else. – Rup Apr 02 '12 at 17:47
  • @Rup the underlying type is always `int` if it is not specified in the enum declaration; otherwise, it is whatever was specified. My previous comment was to say that there is a reasonable argument in favor of an expectation that `bool` switches would behave differently from enum switches. Of course, though it is reasonable, it is incorrect. Even Eric Lippert wrote in the article linked above "This shortcoming of the language design is silly, but frankly, we have higher priorities than fixing this silly case." – phoog Apr 02 '12 at 17:54

5 Answers5

15

When using a switch statement, the compiler does not understand that when you are using a boolean type to switch on there can only be two results.

The error occurs because you do not have a default case.

Don't use a switch for boolean test - use an if statement:

  bool value = true;

  if(value)
  {
      return new Test1StandardChargeCalculator();
  }

  return new Test2StandardChargeCalculator();
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 1
    Okay so this is basically due to short-sighted compilation? – m.edmondson Mar 30 '12 at 08:56
  • 1
    @m.edmondson Why should it? As [Eric Lippert](http://stackoverflow.com/questions/8671427/why-some-types-do-not-have-literal-modifiers) likes to point out, features are unimplemented by default. – SWeko Mar 30 '12 at 08:56
  • 4
    @m.edmondson - Short sighted? Doing switches on booleans looks to me like a programmer error. I would say the compiler is doing the right thing here. You could of course only have one `case` and a `default` - that should also sort out the error (but how silly would a `switch` with a single `case` look like?). – Oded Mar 30 '12 at 08:57
  • @Oded - I know and understand that switch shouldn't be used in this case, I was merely trying to understand why the compiler would report this error (when both cases are catered for). – m.edmondson Mar 30 '12 at 09:00
  • 1
    @m.edmondson - Because adding a special case for booleans would complicate the compiler for a use case that is not common and make the behavior inconsistent with other types. Don't forget that such a feature would need to be written, tested, documented etc, all of which cost. Eric Lippert wrote about how the C# team decides whether a feature goes in or not - I would say that in the cost/benefit analysis this feature would be down on the list (in particular if you share the view that `switch` on booleans is **wrong**. – Oded Mar 30 '12 at 09:04
  • or how about: return value ? new Test1StandardChargeCalculator() : new Test2StandardChargeCalculator(); – bobwah Mar 30 '12 at 09:21
  • @bobwah - One of the many ways to write this logic. Not what the OP was asking though. – Oded Mar 30 '12 at 09:22
  • @Oded - sure just offering alternatives off the back of your code. – bobwah Mar 30 '12 at 11:23
  • @SWeko: of course, when I do point that out I am channelling Raymond Chen, who said that long before I did. – Eric Lippert Mar 30 '12 at 18:17
  • 1
    @EricLippert - I didn't realize you were the new thing to Raymond's old thing ;) – Oded Mar 30 '12 at 18:21
4

Why do you think the compiler should special-case boolean and detect that all possible values have a case statement?

If you were writing a compiler, would you invest development effort and increase the risk of bugs by implementing this?

Joe
  • 122,218
  • 32
  • 205
  • 338
  • i.e. a use case that is unlikely and may actually be a bug in the program :) – Oded Mar 30 '12 at 08:56
  • I agree in principle, but wouldn't the switch use whatever normal data-flow analysis the compiler has and wouldn't that data-flow analysis have special cases for booleans? – Rup Mar 30 '12 at 10:30
4

In Absence of evidence is not evidence of absence Eric Lippert writes about the limitations of 'proofing' that a variable is unassigned and the weaker aim of the compiler in this regard:

that we're not interested in proving for certain that x is unassigned. We're interested in proving for certain that x is assigned! If we can prove that for certain, then x is "definitely assigned". If we cannot prove that for certain then x is "not definitely assigned".

Which does not directly explain this example but note that it is the same issue as :

int x;

if (a < 10) 
   x = 0;
else if (a >= 10)
   x = 1;

y = x; // x is 'unassigned'

We can quickly see that x will always be assigned, the compiler does not even attempt to find out.

H H
  • 263,252
  • 30
  • 330
  • 514
  • An even better article of mine to link to is: http://blogs.msdn.com/b/ericlippert/archive/2009/08/13/four-switch-oddities.aspx – Eric Lippert Mar 30 '12 at 18:08
  • @EricLippert, are these articles available somewhere except of web archive? I thought you've migrated msdn blog to your own, but by some reason can't find first of them there. The second is https://ericlippert.com/2009/08/13/four-switch-oddities/. – Qwertiy Nov 02 '20 at 12:46
  • @Qwertiy: Thanks for the note; I am gradually moving all my old content to ericlippert.com but it is slow going; there's almost a decade of blog posts to move. – Eric Lippert Nov 02 '20 at 21:54
  • @EricLippert, I thought migration was automated :) – Qwertiy Nov 03 '20 at 00:35
  • @Qwertiy: That's a big part of the problem. Microsoft automatically migrated my blog from one blogging platform to another so many times that the formatting is all messed up, the comments are deleted, and so on, which makes it difficult to automate the process further. I'm going through the originals on the Wayback Machine and manually copying them over and reformatting as I go. – Eric Lippert Nov 03 '20 at 01:51
0

To my understanding it is inconsistant to the definition of the switch which says:

If no case expression matches the switch value, then control is transferred to the statement(s) that follow the optional default label. If there is no default label, control is transferred outside the switch.

You are right: there should be no compiler error. So, this might be a case where no answer is the answer. You will have to live with it.

    switch (answer)
    {
    ...
    default:
    return "It is as it is"
    }
benJima
  • 99
  • 1
  • 7
-3

Maybe better solution would be

internal StandardChargeCalculator Create()
{
  StandardChargeCalculator result = null;
  bool value = true;

  switch (value)
  {
    case true:
      result = new Test1StandardChargeCalculator();
      break;
    case false:
      result = new Test2StandardChargeCalculator();
      break;
  }
  return result;
}
JleruOHeP
  • 10,106
  • 3
  • 45
  • 71
  • A better solution would be using `if`... using a `switch` to test a boolean makes no sense – Thomas Levesque Mar 30 '12 at 08:58
  • I know it, but for different cases - where switch is better solution, and you want to use default value to check for exceptions, for example, you can use this approach. And it have only 1 return - it`s simplier to read – JleruOHeP Mar 30 '12 at 09:04
  • Is this also missing a `break`? – Ed Heal Mar 30 '12 at 09:04
  • If, else would be the best choice to check for a bool, this just makes the code more unreadable than it actually is – ganeshran Mar 30 '12 at 09:14