37

I have a few config options in my application along the lines of

const bool ExecuteThis=true;
const bool ExecuteThat=false;

and then code that uses it like

if(ExecuteThis){ DoThis(); }
if(ExecuteThat){ DoThat(); } //unreachable code warning here

The thing is, we may make slightly different releases and not ExecuteThis or ExecuteThat and we want to be able to use consts so that we don't have any speed penalties from such things at run time. But I am tired of seeing warnings about unreachable code. I'm a person that likes to eliminate all of the warnings, but I can't do anything about these. Is there some option I can use to turn just these warnings off?

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • 2
    How significant are those speed penalties? – Matthew Groves Dec 18 '09 at 21:29
  • possibly a lot of extra code put in for code that will "actually" never be executed, and a these comparisons are pretty rich.. probably 30-40 of these per page load. – Earlz Dec 18 '09 at 21:31
  • 1
    Effictive C# suggests using readonly over const in most cases. Things that do not change often or aren't meant to change (speed of light, Millena, etc.) can be done as a const. – Hamish Grubijan Dec 18 '09 at 21:32
  • 1
    This is making me wish C# had static if. (This is a feature of D, a compile-time conditional, which can depend on anything that is fixed at compile time, be it a constant defined in code, a template parameter or whatever.) – Stewart May 01 '17 at 14:54
  • I don't know if it would help solve your problem, but I've just discovered that conditional expressions (`? ... :`) don't trigger this warning, even if the condition is fixed at compile time. Of course, this isn't a general solution, and static if would still be much neater. – Stewart May 01 '17 at 15:10

8 Answers8

61

To disable:

#pragma warning disable 0162

To restore:

#pragma warning restore 0162

For more on #pragma warning, see MSDN.

Please note that the C# compiler is optimized enough to not emit unreachable code. This is called dead code elimination and it is one of the few optimizations that the C# compiler performs.

And you shouldn't willy-nilly disable the warnings. The warnings are a symptom of a problem. Please see this answer.

Zoe
  • 27,060
  • 21
  • 118
  • 148
jason
  • 236,483
  • 35
  • 423
  • 525
  • 4
    Please be sure to read Lasse V. Karlsen's (http://stackoverflow.com/users/267/lasse-v-karlsen) answer (http://stackoverflow.com/questions/1930793/is-there-a-way-to-get-vs2008-to-stop-warning-me-about-unreachable-code/1930840#1930840). All I did is tell you how to do what you wanted. His answer tells you why you should avoid being in this situation in the first place. – jason Dec 18 '09 at 21:41
  • 1
    I agree with this, with the caveat that you should comment in why you are choosing not to use the precompiler. I am guessing it is so you can use the compiler to statically check for errors in the code, even if it isn't being compiled into your app in the current build. I wonder if the C# compiler is smart enough to "optimize" this code out, so that you end up with the same code as if you had used the pre-compiler. – Merlyn Morgan-Graham Dec 18 '09 at 21:45
  • IMNO you shouldn't deactivate the compiler warnings, you should always be informed of the "bad", or "dead" code you write, even if you are conscient of it. The preprocessed statements (#if condition ) could help you in your case. – serhio Dec 18 '09 at 23:05
  • Thanks for this. I needed this because I had to put in a bit of a hack in my code that made an assumption of a certain constant being set to a certain value. I wanted the code in question to vomit appropriately if the assumption was no longer true, and if the constant was not the expected value, to throw an exception when called. So by design, that code is unreachable unless the constant changes. Maybe there's a fancier way to do this (it'd be ideal if the check could be done at compile-time instead) but I wasn't able to find one. – Eliot Dec 16 '14 at 16:36
25

First of all, I agree with you, you need to get rid of all warnings. Every little warning you get, get rid of it, by fixing the problem.

Before I go on with what, on re-read, amounts to what looks like a rant, let me emphasis that there doesn't appear to be any performance penalty to using code like this. Having used Reflector to examine code, it appears code that is "flagged" as unreachable isn't actually placed into the output assembly.

It is, however, checked by the compiler. This alone might be a good enough reason to disregard my rant.

In other words, the net effect of getting rid of that warning is just that, you get rid of the warning.

Also note that this answer is an opinion. You might not agree with my opinion, and want to use #pragma to mask out the warning message, but at least have an informed opinion about what that does. If you do, who cares what I think.

Having said that, why are you writing code that won't be reached?

Are you using consts instead of "defines"?

A warning is not an error. It's a note, for you, to go analyze that piece of code and figure out if you did the right thing. Usually, you haven't. In the case of your particular example, you're purposely compiling code that will, for your particular configuration, never execute.

Why is the code even there? It will never execute.

Are you confused about what the word "constant" actually means? A constant means "this will never change, ever, and if you think it will, it's not a constant". That's what a constant is. It won't, and can't, and shouldn't, change. Ever.

The compiler knows this, and will tell you that you have code, that due to a constant, will never, ever, be executed. This is usually an error.

Is that constant going to change? If it is, it's obviously not a constant, but something that depends on the output type (Debug, Release), and it's a "#define" type of thing, so remove it, and use that mechanism instead. This makes it clearer, to people reading your code, what this particular code depends on. Visual Studio will also helpfully gray out the code if you've selected an output mode that doesn't set the define, so the code will not compile. This is what the compiler definitions was made to handle.

On the other hand, if the constant isn't going to change, ever, for any reason, remove the code, you're not going to need it.

In any case, don't fall prey to the easy fix to just disable that warning for that piece of code, that's like taking aspirin to "fix" your back ache problems. It's a short-term fix, but it masks the problem. Fix the underlying problem instead.

To finish this answer, I'm wondering if there isn't an altogether different solution to your problem.

Often, when I see code that has the warning "unreachable code detected", they fall into one of the following categories:

  1. Wrong (in my opinion) usage of const versus a compiler #define, where you basically say to the compiler: "This code, please compile it, even when I know it will not be used.".
  2. Wrong, as in, just plain wrong, like a switch-case which has a case-block that contains both a throw + a break.
  3. Leftover code from previous iterations, where you've just short-circuited a method by adding a return at some point, not deleting (or even commenting out) the code that follows.
  4. Code that depends on some configuration setting (ie. only valid during Debug-builds).

If the code you have doesn't fall under any of the above settings, what is the specific case where your constant will change? Knowing that might give us better ways to answer your question on how to handle it.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 4
    "It is, however, checked by the compiler. This alone might be a good enough reason to disregard my rant." -- I would say thats my reason for disregarding it... I hate having some configurations that may or may not compile.. I like to have warning-less code(as in, I fix them all) but I know that the cause of the warning is really nothing significant... (also, it's not like I'm disabling the warning for my whole project) – Earlz Dec 21 '09 at 15:03
  • May i add a note. If you are using things like 1. #if DEBUG some return (e.g. throw, return, ...) #endif and have code afterwards the compiler will see the code as unreachable, even if it is reachable in release code. So code is there, it will be executed, but compiler warns about somethign not reachable - funny, eh? – Offler Jan 13 '15 at 10:25
  • 2
    @Offler No, that is incorrect, it does not do that. If you compile it for DEBUG, which thus includes the return, then yes, the rest of the method will give you a warning for unreachable. However, if you compile it for RELEASE, which does not include the return, you will not get a warning. The compiler is right in both cases. – Lasse V. Karlsen Jan 13 '15 at 11:17
  • This is a condition. If the compilers warns for unreachable code there is still nothing to fix and just irrelevant junk from compiler. – Offler Jan 21 '15 at 13:19
  • Sure you can fix it, if you conditionally include a return or not, you should conditionally include the rest of the method as well. – Lasse V. Karlsen Jan 21 '15 at 16:07
  • I agree with the others not wanting to use the precompiler because it means the code might not compile in certain configurations, but you won't find out until you try (for RELEASE, that might not be very often). Also, following the warnings of the compiler, you can't really do _anything_ meaningful with a `const bool`... – Svend Hansen Apr 29 '15 at 11:38
  • 3
    While I understand what you're saying, I feel like the `#define` syntax in C# leaves a lot to be desired. For example, a typo like `#if MYCONSTENT` will end up being always false instead of generating a compiler error like `if(MyConstent)`, it feels safer to have an error. Also if you later end up removing a `const`, you can just delete it and then go through and fix the errors, whereas with a `#define` const you have to use Ctrl+F, and again, if you miss one, `#if` will just be always false. Also `#define` constants are always file scoped, and there's no `#include` like there is in C/C++. – jrh May 22 '18 at 13:44
  • The other thing is, even assuming you /don't/ make a typo in your `#if`, from my experience it is very easy to forget the exact semantics of how the variable was defined, for example, you might mean to type `FEATURE_DISABLED`, but you might instead type `FEATURE_DISABLE`, `FEATURE_IS_DISABLED`, `FEATURE_ENABLED`, etc., and unless you `#define` / `#undef` all near synonyms too in some sort of `#if` block, these kind of errors will probably happen. IMO the possibility of mistakes and the limited tools to prevent the mistakes doesn't justify the usage of `#define` just to avoid a compiler warning – jrh Jul 10 '18 at 13:47
  • What about having a `switch` statement with `case [x]: if ([cond]) return 0; else return 1; break;` as it irks me to *not* have it end with `break;` – Elaskanator Nov 12 '21 at 13:49
  • I know this is old, but the indestructible dogma underlying the orthodoxy of this (and similar "thou shalt obey thy compiler" responses) just never dies. _"Why is the code even there? It will *never* execute."_ "Never" with bold. Well, the compiler is not your god. It's an _imperfect_ tool for the _imperfect_ ideas you are trying to express using the already _imperfect_ abstractions of the language the compiler _imperfectly_ translates etc. Glorifying the priority of satisfying every corner case of the compiler during this balancing act is like keeping your boots always polished in the trench. – Sz. Feb 06 '22 at 17:39
  • Andy yes, _of course_ it is invaluable to eliminate at least that much of the imperfections that the compiler can notice and warn about. My point is not about that, obviously. My point is about the relentless "all or nothing" orthodoxy that claims that every single warning is a sin and the compiler always knows better, even though much of the rest of every ongoing project is inevitably in flux, and therefore the truth of the compiler (and the code) is ephemeral. So my point is about that "never", with bold. Always keep your tools clean, yes, but don't polish your boots during combat. – Sz. Feb 06 '22 at 17:54
22

What about using preprocessor statements instead?

#if ExecuteThis
    DoThis();
#endif

#if ExecuteThat
    DoThat();
#endif
Jason Down
  • 21,731
  • 12
  • 83
  • 117
  • 1
    +1. That way the code you aren't using doesn't even get compiled into the assembly. – David Dec 18 '09 at 21:35
  • 2
    I like this method, but I value the fact that my code must always compile no matter what the preprocessor directives are.. – Earlz Dec 18 '09 at 21:37
  • 2
    Preprocessor statements are definately the way to set flags at compile-time, and will ensure the "unreachable code" won't be compiled, much more safely than a const bool. Plus, you can make extra configurations besides just "Debug" and "Release" that will insert these defines, such as "Debug ExecuteThis". – Will Eddins Dec 18 '09 at 21:38
  • I so wish I could have two answers :) I think I'll be following a hybrid approach... – Earlz Dec 18 '09 at 21:39
  • They're giving you warnings for a reason, because this is the way it should be done. – Will Eddins Dec 18 '09 at 21:40
  • 2
    Note that using "if (x) { ... }", where x is defined as `const Boolean x = false;` will in fact not put the code into the assembly. The warning is there to tell you that that just happened, and that might be a problem. – Lasse V. Karlsen Dec 18 '09 at 21:52
  • 1
    I disagree with the notion that "this is the way it should be done." I have seen enough code to know that there is no right way. However, there are plenty of ways that are *probably* wrong. That the compiler warns me about those and thus forces me to take a stand: Use this code, or change it, is a good thing. However, sometimes the right choice is the wrong one (if you know what I mean, then you know what I mean.) – Lasse V. Karlsen Dec 18 '09 at 23:01
11

Well, #pragma, but that is a but grungy. I wonder if ConditionalAttribute would be better - i.e.

[Conditional("SOME_KEY")]
void DoThis() {...}
[Conditional("SOME_OTHER_KEY")]
void DoThis() {...}

Now calls to DoThis / DoThat are only included if SOME_KEY or SOME_OTHER_KEY are defined as symbols in the build ("conditional compilation symbols"). It also means you can switch between them by changing the configuration and defining different symbols in each.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • +1 One can also resort to auto-generated code if things get complex. – Hamish Grubijan Dec 18 '09 at 21:34
  • 1
    I can't even begin to express how much I *hat*^H^H^H don't like "Conditional". Sure, it's nice and it does exactly what it is supposed to, but it defines *when* it is supposed to do something *somewhere else* than where I want it to do it. When I read the code that says "if (x) DoThis();", I expect that method to be called, not to be masked out silently. If there is a chance that this method call is going to be masked out, I want that to be explicitly expressed at the call-site, not with the method. – Lasse V. Karlsen Dec 18 '09 at 22:27
  • 1
    I guess it depends a bit on what the method is. I'm OK with trace/log/debug etc steps silently removing themselves. – Marc Gravell Dec 18 '09 at 23:06
3

The fact that you have the constants declared in code tells me that you are recompiling your code with each release you do, you are not using "contants" sourced from your config file.

So the solution is simple: - set the "constants" (flags) from values stored in your config file - use conditional compilation to control what is compiled, like this:

#define ExecuteThis
//#define ExecuteThat

public void myFunction() {
#if ExecuteThis
    DoThis();
#endif
#if ExecuteThat
    DoThat();
#endif
}

Then when you recompile you just uncomment the correct #define statement to get the right bit of code compiled. There are one or two other ways to declare your conditional compilation flags, but this just gives you an example and somewhere to start.

slugster
  • 49,403
  • 14
  • 95
  • 145
3

The quickest way to "Just get rid of it" without modifying your code would be to use

#pragma warning disable 0162

On your Namespace, class or method where you want to supress the warning.

For example, this wont throw the warning anymore:

#pragma warning disable 0162
namespace ConsoleApplication4
{
  public class Program
  {
    public const bool something = false;

    static void Main(string[] args)
    {
        if (something) { Console.WriteLine(" Not something" ); }

    } 
 }

However be warn that NO METHOD inside this namespace will throw the warning again... and well.. warnings are there for a reason (what if it happened when you did NOT planned it to be unreachable?)

I guess a safer way would be to write the variables in a configuration file, and read them from there at the beginning of the program, that way you don't even need to recompile to have your different versions/releases! Just change the app file and go :D.

about the speed penalty.. yes.. making it this way would inquire in a speed penalty... compared to using const but unless you are really worried about wating 1/100 of a millisecond more.. I would go for it that way.

Francisco Noriega
  • 13,725
  • 11
  • 47
  • 72
3

Here's a trick:

    bool FALSE = false;
    if (FALSE) { ... 

This will prevent the warning. Wait. I know there's all this "You should not use that, why have code that is not executed?". Answer: Because during development you often need to set up test code. Eventually you will get rid of it. It's important that code it is there during development, but not executed all the time.

Sometimes you want to remove code execution temporarily, for debugging purposes.

Sometimes you want to truncate execution of a function temporarily. You can use this to avoid warnings:

...code.. { bool TRUE = true; if (TRUE) return; } ...more code...

These things avoid the warning. You might say, if temporary, one should keep the warning in. yes... but again... maybe you should not check it in that way, but temporarily it is useful to get the warning out, for example when spending all day debugging complex collision code.

So, you may ask, why does it matter? Well, these warnings get very annoying when I press F4 to go to the first error, and get some damn 10 warnings first instead and I am knee deep in debugging.

Use the #pragma, you say. Well, that would be a good idea, except that I can't find a way to do that globally on my entire project.. or in a way that will work with Unity3D, which is what I code in C# for. Oh, how useful #include would be.

Never mind, use #if ! Well... yes... but sometimes they are not what you want. They make the code messy and unreadable. You have to bracket your code with them just right. Putting if(false) in front of a block is just so much easier... no need to delimit the block, the braces do that.

What I do is make a nice globally accessible FALSE and TRUE and use them as I need do avoid errors.

And if I want to check if I am actually using them, I can search for all references, or more crudely, but just as effectively, remove them and thus be forced to look at every occurrence of this little trick.

Dino Dini
  • 433
  • 3
  • 6
  • On Visual Studio 2013 that still emits the warning the OP is trying to stop. – Cameron May 02 '15 at 16:50
  • Yeh, figures. So then you have to make a function that returns true or false instead and use that. – Dino Dini May 03 '15 at 17:32
  • This works in VS 2015. It doesn't require an annoying #endif or #pragma restore. And it doesn't hide errors that an unrestored pragma could. – Tod Dec 12 '16 at 05:53
  • 2
    This answer is exactly what I wanted! The currently accepted answer is kind of snobbish. – GregorMohorko Jan 17 '17 at 16:41
2

The easiest way is to stop writing unreachable code :D #DontDoThat

BenAlabaster
  • 39,070
  • 21
  • 110
  • 151