24

When assigning a default default-value to a field (here false to a bool), FxCop says:

Resolution   : "'Bar.Bar()' initializes field 'Bar.foo' 
               of type 'bool' to false. Remove this initialization 
               because it will be done automatically by the runtime."

Now, I know that code as int a = 0 or bool ok = false is introducing some redundancy, but to me it seems a very, very good code-practice, one that my teachers insisted on righteously in my opinion.

Not only is the performance penalty very little, more importantly: relying on the default is relying on the knowledge of each programmer ever to use a piece of code, on every datatype that comes with a default. (DateTime?)

Seriously, I think this is very strange: the very program that should protect you from making all too obvious mistakes, is suggesting here to make one, only for some increased performance? (we're talking about initialization code here, only executed once! Programmers who care that much, can of course omit the initialization (and should probably use C or assembler :-) ).

Is FxCop making an obvious mistake here, or is there more to it?

Two updates :

  1. This is not just my opinion, but what I have been taught at university (Belgium). Not that I like to use an argumentum ad verecundiam, but just to show that it isn't just my opinion. And concerning that:

  2. My apologies, I just found this one:

    Should I always/ever/never initialize object fields to default values?

Community
  • 1
  • 1
Peter
  • 47,963
  • 46
  • 132
  • 181

6 Answers6

11

There can be significant performance benefits from this, in some cases. For details, see this CodeProject article.

The main issue is that it is unnecessary in C#. In C++, things are different, so many professors teach that you should always initialize. The way the objects are initialized has changed in .NET.

In .NET, objects are always initialized when constructed. If you add an initializer, it's possible (typical) that you cause a double initialization of your variables. This happens whether you initialize them in the constructor or inline.

In addition, since initialization is unnecessary in .NET (it always happens, even if you don't explicitly say to initialize to the default), adding an initializer suggests, from a readability standpoint, that you are trying to add code that has a function. Every piece of code should have a purpose, or be removed if unnecessary. The "extra" code, even if it was harmless, suggests that it is there for a reason, which reduces maintainability.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 2
    unnecessary for who or what? You of course code for persons to, for a machine comments are unnecessary too, this doesnot mean they are unnecessary perse – Peter Apr 08 '09 at 17:29
  • You can put it in as a comment, just as easily as a statement, and not create the same performance impacts. It's like having code that is unreachable - it may provide something to you, but I'd rather have it as a comment than leave unreachable code in my methods. – Reed Copsey Apr 08 '09 at 17:30
  • 2
    The difference with a comment, is when I say int i = 0; I want i to be zero, the statement is logical. Even when compiled with a future compiler that has other defaults (unlikely for int ofcourse) – Peter Apr 08 '09 at 17:43
  • And a question : if you want a date to be initialized on 1/1/1, do you omit this value because it's unnecessary, and do you seriousliy think this would be a good idea? – Peter Apr 08 '09 at 17:48
  • @Peter: You're guaranteed that an int will always be defaulted to 0 by the CLR spec - this isn't a compiler issue, but rather a runtime/platform issue. If you want a date to be initialized to a non-default value, by all means initialize it, but only if you're using a non-default value. – Reed Copsey Apr 08 '09 at 17:51
  • atReed (my at won't work for some reasen :)) but with a date, 1/1/1 happens to be the default, ommiting that don't seem clear nor a good practice if you mean that (indeed historical) date. – Peter Apr 08 '09 at 17:57
  • @Peter: This is a private member variable. In that case (which is kind of an extreme case), I'd probably make a comment/remark that I did want that date, and still eliminate it. FxCop won't complain, though, if you specify the date as = new DateTime(1,1,0001); – Reed Copsey Apr 08 '09 at 18:00
  • ...Since that's not the default constructor. It will only complain if you do date = new DateTime(); – Reed Copsey Apr 08 '09 at 18:01
  • @Peter I see your point, but in this case, your default value should be a constant (or a static readonly value) to make it more explicit. int i = DEFAULT_WHATEVER; or DateTime d = DEFAULT_BIRTH_DATE; instead of int i = 0; and DateTime d = new DateTime(1, 0, 1); – Michael Meadows Apr 08 '09 at 18:04
  • atReed : The "extra" code, even if it was harmless, suggests that it is there for a reason, which reduces maintainability. --> it is there for a reason, for clarity of course, and for unforseen future uses. The widely unneeded accepted curly braces after an if are there for the same – Peter Apr 08 '09 at 18:18
  • reason `if (test) { doIt(); }` atMichael : tx – Peter Apr 08 '09 at 18:20
  • The curly braces are for readability, but have no effect on the compiled IL. The initializer does, however, change the runtime behavior of your code. You are free to turn off this warning in FxCop, however, this is one that I agree with (it took me a long time to agree with it, though...) – Reed Copsey Apr 08 '09 at 18:44
  • 2
    @ReedCopsey I reran the tests and apparently the tests are wrong (and always were). There is no performance difference. I posted my results below. – Daniel A.A. Pelsmaeker Apr 02 '13 at 14:58
6

Reed Copsey said specifying default values for fields impacts performance, and he refers to a test from 2005.

public class A
{
    // Use CLR's default value
    private int varA;
    private string varB;
    private DataSet varC;
}

public class B
{
    // Specify default value explicitly
    private int varA = 0;
    private string varB = null;
    private DataSet varC = null;
}

Now eight years and four versions of C# and .NET later I decided to repeat that test under .NET Framework 4.5 and C# 5, compiled as Release with default optimizations using Visual Studio 2012. I was surprised to see that there is still a performance difference between explicitly initializing fields with their default values and not specifying a default value. I would have expected the later C# compilers to optimize those constant assignments away by now.

No init: 512,75    Init on Def: 536,96    Init in Const: 720,50
Method No init: 140,11    Method Init on Def: 166,86

(the rest)

So I peeked inside the constructors of classes A and B in this test, and both are empty:

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void [mscorlib]System.Object::.ctor()
    IL_0006: ret
} // end of method .ctor

I could not find a reason in the IL why explicitly assigning default constant values to fields would consume more time. Apparently the C# compiler does optimize the constants away, and I suspect it always did.

So, then the test must be wrong... I swapped the contents of classes A and B, swapped the numbers in the result string, and reran the tests. And lo and behold now suddenly specifying default values is faster.

No init: 474,75    Init on Def: 464,42    Init in Const: 715,49
Method No init: 141,60    Method Init on Def: 171,78

(the rest)

Therefore I conclude that the C# compiler correctly optimizes for the case where you assign default values to fields. It makes no performance difference!


Now we know performance is really not an issue. And I disagree with Reed Copsey's statement "The 'extra' code, even if it was harmless, suggests that it is there for a reason, which reduces maintainability." and agree with Anders Hansson on this:

Think long term maintenance.

  • Keep the code as explicit as possible.
  • Don't rely on language specific ways to initialize if you don't have to. Maybe a newer version of the language will work differently?
  • Future programmers will thank you.
  • Management will thank you.
  • Why obfuscate things even the slightest?

Future maintainers may come from a different background. It really isn't about what is "right" it is more what will be easiest in the long run.

Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
5

FxCop has to provide rules for everyone, so if this rule doesn't appeal to you, just exclude it.

Now, I would suggest that if you want to explicitly declare a default value, use a constant (or static readonly variable) to do it. It will be even clearer than initializing with a value, and FXCop won't complain.

private const int DEFAULT_AGE = 0;

private int age = 0; // FXCop complains
private int age = DEFAULT_AGE; // FXCop is happy

private static readonly DateTime DEFAULT_BIRTH_DATE = default(DateTime);

private DateTime birthDate = default(DateTime); // FXCop doesn't complain, but it isn't as readable as below
private DateTime birthDate = DEFAULT_BIRTH_DATE; // Everyone's happy
Pang
  • 9,564
  • 146
  • 81
  • 122
Michael Meadows
  • 27,796
  • 4
  • 47
  • 63
4

FX Cop sees it as adding unnecessary code and unnecessary code is bad. I agree with you, I like to see what it's set to, I think it makes it easier to read.

A similar problem we encounter is, for documentation reasons we may create an empty constructor like this

/// <summary>
/// a test class
/// </summary>
/// <remarks>Documented on 4/8/2009  by richard</remarks>
public class TestClass
{
    /// <summary>
    /// Initializes a new instance of the <see cref="TestClass"/> class.
    /// </summary>
    /// <remarks>Documented on 4/8/2009  by Bob</remarks>
    public TestClass()
    {
        //empty constructor
    }        
}

The compiler creates this constructor automatically, so FX cop complains but our sandcastle documentation rules require all public methods to be documented, so we just told fx cop not to complain about it.

Pang
  • 9,564
  • 146
  • 81
  • 122
Bob The Janitor
  • 20,292
  • 10
  • 49
  • 72
  • unnecessary code is bad of course, but this code can become necessary in the unlikely event a default will be changed in the future and this code is recompiled. – Peter Apr 08 '09 at 17:44
  • @Peter: Defaults for value types are guaranteed to always initialize to zeros. It's part of the CLR specification itself. There is no way for a value type default to change. Reference types are the same - they're guaranteed, by spec, to default to null. – Reed Copsey Apr 08 '09 at 18:02
  • @Bob The Janitor, doing things that don't feel right just to satisfy a tool usually ends poorly! ;) – Michael Meadows Apr 08 '09 at 18:16
  • it's not doing something to satisfy a tool, I deliberately set the rule that enforces it. If you look at the XML doc the Remarks state when something was Documents, this should be the same time it was created, this then places when something was created into our documentation. – Bob The Janitor Apr 08 '09 at 19:06
2

It's relies not on every programmer knowing some locally defined "corporate standard" which might change between at any time, but on something formally defined in the Standard. You might as well say "don't using x++ because that relies on the knowledge of every programmer.

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • completely different issues imo, (between () has DateTime a default, and what is it's value? What does x-- do? I think the answer to the latter 100% of the programmers know, the answer to the first - if we're lucky - 50%) – Peter Apr 08 '09 at 17:32
  • First of all, it equals "default(DateTime)". Second, under what circumstances would you care what the actual value is? – James Curran Apr 09 '09 at 03:54
2

You have to remember that FxCop rules are only guidelines, they are not unbreakable. It even says so on the page for the description of the rule you mentioned (http://msdn.microsoft.com/en-us/library/ms182274(VS.80).aspx, emphasis mine):

When to Exclude Warnings:

Exclude a warning from this rule if the constructor calls another constructor in the same or base class that initializes the field to a non-default value. It is also safe to exclude a warning from this rule, or disable the rule entirely, if performance and code maintenance are not priorities.

Now, the rule isn't entirely incorrect, but like it says, this is not a priority for you, so just disable the rule.

casperOne
  • 73,706
  • 19
  • 184
  • 253