GOTCHA 12 Compiler warnings may not be benign


GOTCHA #12 Compiler warnings may not be benign

A compiler aids developers by checking for syntax consistency, and tries to eliminate (or at least reduce) the possibility of errors. However, there are certain anomalies that the compiler takes less seriously than you might want it to. Reporting them as warnings instead of errors may lead to code that compiles but does not behave the way you expect. I urge you to treat warnings as errors to make sure they don't escape your notice.

I have been preaching this since I started working with .NET. There were times when I wondered how much I should emphasize it, but I was reminded recently when a client asked me to help integrate a new product with an existing one.

I began by fetching the code from the source code control system and compiled it on my machine. Since I had not registered all the necessary components, I got errors. When I went to resolve them, I found several warnings scattered among the errors. My first impulse was to ignore my principles and practices, fix the errors, and finish my task. (After all, I was asked to integrate, not to preach.) However, I get very nervous leaving warnings in my code. So, out of curiosity, I started browsing through the warnings. I could not believe my eyes when I saw the following "warning":

 warning CS0665: Assignment in conditional expression is always constant; did you mean to use == instead of = ? 

The offending code resembled the following if-clause:

 if (m_theTextBox.Visible = true) 

It was scary to see this crucial mistake in production code. Somehow, it had slipped through the testing and debugging process.

Once I saw this, I looked at the other warnings with a suspicious eye. The next one I encountered said that a method was hiding a method in its base class, and suggested that I use the new keyword (shadows in VB.NET). Here's the problem: first a method is marked virtual in the base class (overridable in VB.NET); then a derived class implements a method with the same name and signature without marking it as override (overrides in VB.NET).

The result (as discussed in Gotcha #44, "Compilers are lenient toward forgotten override/overrides") is that the derived method ends up hiding or shadowing the base method instead of overriding it. This leads to behavior that is outright wrong. What is worse is that Visual Studio hides the warning under the rug, so to speak, as Example 2-1 shows.

Example 2-1. Warnings reported by Visual Studio

C# (Warnings)

 using System; namespace TreatWarningsAsError {     public class Base     {         public virtual void foo() {}     }       public class Derived : Base     {          public void foo() {}     }     public class Test     {         [STAThread]         static void Main(string[] args)         {              int val;             Console.WriteLine("Test");         }     } } 

VB.NET (Warnings)

 Public Class Base     Public Overridable Sub foo()     End Sub End Class Public Class Derived      Inherits Base      Public Sub foo()     End Sub End Class Public Class Test     Public Shared Sub Main(ByVal args() As String)          Dim val As Integer         Console.WriteLine("Test")     End Sub End Class 

When you compile the C# code in Example 2-1, the output window displays what you see in Figure 2-1.

Figure 2-1. Visual Studio output window for C# code in Example 2-1


Since the build succeeded, you have no reason to look for warnings, right? Well, no, not exactly.

If you scroll up to view the compiler messages, you will find:

 : warning CS0114: 'TreatWarningsAsError.Derived.foo()' hides inherited member 'TreatWarningsAsError.Base.foo()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. : warning CS0168: The variable 'val' is declared but never used 

There are two warnings. One says that the method foo() in Derived hides the method foo() in Base. The other says that the variable val is declared but never used. While the second is benign, the first one definitely is not.

You may notice that Visual Studio points out warnings by putting a squiggly line on the offending statement. So why not just find the squiggly lines and fix the problems? Well, that might work in a small application. But in a large system, where you may have hundreds of classes, a change in one class can ripple through the entire system. You can't search every single file looking for squiggly lines.

The problem here is more fundamental: Certain cases, such as the missing override/overrides or the use of = instead of ==, are key programming mistakes and should be treated as errors, not warnings.

I strongly recommend that you configure the compiler to treat warnings as errors. In Visual Studio, you can do this by going into your project's properties.

In a C# project, right click on the project name in the Solutions Explorer and click on Properties. In the resulting dialog, go to the Build entry under Configuration Properties. Change the value for the TReat Warnings As Errors property from False to true (you can easily do this with just a double click on the property name), as shown in Figure 2-2. (Figure 2-3 shows how to change the settings for a VB.NET project.)

After you make these changes, the incorrect override of the foo() method appears as an error. However, the benign warning of val not being used has disappeared in the C# version. In the VB.NET version, it did not appear in the first place.

Fortunately, you don't have to change these settings for every project you create. You can change them at the system level so each new project will have this setting. You do that by modifying the appropriate template.

For C#, you can find these templates in the VC#\VC#Wizards directory where Visual Studio .NET is installed. For instance, on my machine, it is under the C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\VC#Wizards directory. There are four template files: default.csproj (for console applications), DefaultDll.csproj (for DLL class library projects), DefaultWebProject.csproj (for ASP.NET applications), and DefaultWinExe.csproj (for Windows applications). Example 2-2 shows you how

Figure 2-2. Setting Treat Warnings as Errors in a C# project


Figure 2-3. Setting Treat Warnings as Errors in a VB.NET project


to add an entry to the template file to set treat Warnings As Errors to true for every C# console project you create.

Example 2-2. Template entry to set Treat Warnings As Errors projects on C#
 <VisualStudioProject>      <CSHARP>        <Build>             <Settings OutputType = "Exe" NoStandardLibraries = "false" >                 <Config                     Name = "Debug"                     DebugSymbols = "true"                     Optimize = "false"                     OutputPath = ".\bin\Debug"                     EnableUnmanagedDebugging = "false"                     DefineConstants = "DEBUG;TRACE"                     WarningLevel = "4"                 IncrementalBuild = "false"                  TreatWarningsAsErrors = "true"                 />               <Config                     Name = "Release"                     DebugSymbols = "false"                     Optimize = "true"                     OutputPath = ".\bin\Release"                     EnableUnmanagedDebugging = "false"                        DefineConstants = "TRACE"                         WarningLevel = "4"                 IncrementalBuild = "false"                  TreatWarningsAsErrors = "true"                 />             </Settings>         </Build>         <Files>             <Include/>             <Exclude/>         </Files>     </CSHARP> </VisualStudioProject> 

For VB.NET, the templates for different types of projects are located in different subdirectories under the vb7\VBWizards directory. On my system, the file C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7\VBWizards is the Wizard directory. The template for all console applications is the file ...\Vb7\VBWizards\ConsoleApplication\Templates\1033\ConsoleApplication.vbproj.

Example 2-3 shows how you add an entry to the template file to set treat Warnings As Errors to true for every new VB.NET console project.

Example 2-3. Template entry to set Treat Warnings As Errors on VB.NET projects
 <VisualStudioProject>     <VisualBasic>         <Build>             <Settings OutputType = "Exe" StartupObject = "" >                 <Config                     Name = "Debug"                     DebugSymbols = "true"                     DefineDebug = "true"                     DefineTrace = "true"                     IncrementalBuild = "true"                     OutputPath = "bin"                      TreatWarningsAsErrors = "true"                 />                 <Config                     Name = "Release"                     DebugSymbols = "false"                     DefineDebug = "false"                     DefineTrace = "true"                     IncrementalBuild = "false"                     Optimize = "true"                     OutputPath = "bin"                      TreatWarningsAsErrors = "true"                 />             </Settings>             <References>                 <Reference Name = "System" />                 <Reference Name = "System.Data" />                 <Reference Name = "System.XML" />                      </References>             <Imports>                 <Import Namespace = "Microsoft.VisualBasic" />                 <Import Namespace = "System" />                 <Import Namespace = "System.Collections" />                 <Import Namespace = "System.Data" />                 <Import Namespace = "System.Diagnostics" />             </Imports>         </Build>         <Files>             <Include>             </Include>         </Files>     </VisualBasic> </VisualStudioProject> 

Treating warnings as errors has side effects, however.

The main side effect of configuring the project setting to treat warnings as errors is that benign warnings will show up as errors, thus terminating the compilation. Example 2-4 shows a simple example of a class named AService created as part of a class library.

Example 2-4. Sample code with benign warnings

C# (WarningSideEffect)

 using System; namespace TreatWarningsAsErrorSideEffect {     /// <summary>     /// Summary description for Class1.     /// </summary>     public class AService     {         /// <summary>         /// Documentation for Method1         /// </summary>         public void Method1()         {         }         public int Method2()         {             return 0;         }     } } 

VB.NET (No Example in VB.NET)

In the above example, while Method1() has the XML documentation tags, Method2() does not. This is not unusual. While you may want to document each method you write, sometimes there are methods that, for some reason, you don't want to. (A method whose sole purpose is to test some feature of your code is a good example.) When you compile the above code with treat Warnings As Errors set to true, the warning becomes an error:

    error CS1591: Missing XML comment for publicly visible type or member    'TreatWarningsAsErrorSideEffect.AService.Method2()' 

There are two solutions to this problem. One is to go ahead and write some documentation, however sketchy, for each method. Or you can suppress warnings of this kind, as shown in Figure 2-4.

But be careful about suppressing warnings. You might not really want to suppress certain warnings. Depending on the case, there may be other alternatives or workarounds.

Figure 2-4. Asking certain warnings to be suppressed


IN A NUTSHELL

Not all compiler warnings are benign. Some severe problems are reported as warnings.

Therefore, I strongly recommend that you configure the compiler to treat warnings as errors. You can do this on a per-project basis, or you can modify the Visual Studio templates to affect all future projects you create.

SEE ALSO

Gotcha #44, "Compilers are lenient toward forgotten override/overrides."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net