Should I explicitly initialize all member variables?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I come from a background of Ada and C++ programming, where it was considered
good practice to explicitly initialize every variable.

Now that I'm programming in C# I think that it would be best NOT to
initialize class members, because every type has well defined initialization
anyway.

eg.

class C
{

int i = 0; // redundant

int j; // better?

MyClass m = null; // redundant

MyClass m; // better?
}

What's the best practice?

TIA,

Javaman
 
Javaman59,

The best thing to do is to initialize every variable.
Then, there's always a default value for every variable.
It should probably make your code 'neater' and easier to decipher, it
makes thing clear.

Sorry if this isn't what you like but,

Seen Sharp
 
I must STRONGLY disagree. You should not initialize every variable to
its default value as that adds extra overhead. The variable
initialization is moved to the default constructor if you initialize it
by declaring it like this:

class myclass
{
int i = 0;
}

c# for above would generate a constructor and inside you would see
this.i = 0;

assignment.

Waste of cycles man.
 
Thanks for the replies. I think I'll go with my initial preference, and two
out of three replies, and not initialize.

Regards,

Stephen
 
Brian Delahunty said:
I would say not to initialize them as it adds extra code to the underlying
MSIL which in the end takes longer to execute.

Does the JIT generate any code when a field is initialized to its default
value? (Real question, not rhetorical; I have no idea.)
 
Mike Schilling said:
Does the JIT generate any code when a field is initialized to its default
value? (Real question, not rhetorical; I have no idea.)

Yes, it seems to. Here's a quick pair of test programs:

using System;

public class TestWithInit
{
int a0=0, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0, a9=0;
int b0=0, b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0, b8=0, b9=0;

static void Main()
{
DateTime start = DateTime.Now;
for (int i=0; i < 100000000; i++)
{
new TestInit();
}
DateTime end = DateTime.Now;
Console.WriteLine (end-start);
}
}

and:

using System;

public class TestNoInit
{
int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;

static void Main()
{
DateTime start = DateTime.Now;
for (int i=0; i < 100000000; i++)
{
new TestNoInit();
}
DateTime end = DateTime.Now;
Console.WriteLine (end-start);
}
}

On both .NET 2.0 beta 2 and .NET 1.1, the version without explicit
initialisation is faster than the version with initialisation - with or
without optimisation turned on. The difference is actually reasonably
significant - but only in a test where nothing other than object
creation (and GC, obviously) occurs.

I would personally be very reluctant to change any coding habits based
on that though.
 
Jeff Louie said:
Javamman.. The following two lines of code are NOT equivalent in C#.

MyClass m; // better?<

The second line simply creates an unitialized variable. It does not
default to null.

Yes it does - if it's a member variable. If it's a *local* variable it
remains uninitialised, but the subject line makes it clear that the
question is about member variables. From the spec, section 12.2 (ECMA
numbering):

<quote>
The following categories of variables are automatically initialized to
their default values:

* Static variables.
* Instance variables of class instances.
* Array elements.

The default value of a variable depends on the type of the variable and
is determined as follows:

* For a variable of a value-type, the default value is the same as
the value computed by the value-type's default constructor (11.1.1).
* For a variable of a reference-type, the default value is null.

There are a couple of slight errors in that, in the Java bit:

4) Value types *don't* actually derive from anything - only the
reference type which is used for boxing the value type derives
(indirectly) from Object. It's all a bit odd, but is spelled out in the
CLI spec.

9) Java has enums now too - they're very different to C# ones though
(and far superior, IMO).
 
Jon Skeet said:
Yes, it seems to. Here's a quick pair of test programs:

using System;

public class TestWithInit
{
int a0=0, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0, a9=0;
int b0=0, b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0, b8=0, b9=0;

static void Main()
{
DateTime start = DateTime.Now;
for (int i=0; i < 100000000; i++)
{
new TestInit();
}
DateTime end = DateTime.Now;
Console.WriteLine (end-start);
}
}

and:

using System;

public class TestNoInit
{
int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9;

static void Main()
{
DateTime start = DateTime.Now;
for (int i=0; i < 100000000; i++)
{
new TestNoInit();
}
DateTime end = DateTime.Now;
Console.WriteLine (end-start);
}
}

On both .NET 2.0 beta 2 and .NET 1.1, the version without explicit
initialisation is faster than the version with initialisation - with or
without optimisation turned on. The difference is actually reasonably
significant - but only in a test where nothing other than object
creation (and GC, obviously) occurs.

I would personally be very reluctant to change any coding habits based
on that though.

Me too (even if my habit weren't to leave such initializations off.)

But I find your results odd; it's a simple enough JIT optimization to make.
 
No it's not. The JIT would have to compare each value of the initializer
with the default value, this would take much more time than a simple
assignment.

Willy.
 
The JIT would have to do this comparison once, at code-generation time,
while the assignment has to be done every time the object is instantiated.
Assuming the JIT has an up-to-date optimizer built it to it, one that does
loop unrolling, common subexpression elimination, peephole optimization (and
probably lots of things invented since I last studied this stuff:-:), it's
doing much more complex transformations than this one.
 
Mike Schilling said:
The JIT would have to do this comparison once, at code-generation time,

No, it must be done whenever an instance of the class is created, as
guaranteed by the CLI, else this (somewhat contrieved but valid) sample
would fail...

class Foo
{
string s = Bar.s;
public void M1()
{
Console.WriteLine(this.s);
}
}

class Bar
{
internal static string s;
}
class Test
{
static void Main()
{
Foo f1 = new Foo();
f1.M1();
Bar.s = "Hello";
Foo f2 = new Foo();
f2.M1();
}
}


Willy.
 
Willy Denoyette said:
No, it must be done whenever an instance of the class is created, as
guaranteed by the CLI, else this (somewhat contrieved but valid) sample
would fail...

But that's not the same situation. It's one thing for an initializer to
take a value from elsewhere - that has to be done dynamically. It
wouldn't be hard for the JIT to realise that initializers were taking
*constant* values which were also the default ones, and just skip that
initialization step.
 
Willy Denoyette said:
No, it must be done whenever an instance of the class is created, as
guaranteed by the CLI, else this (somewhat contrieved but valid) sample
would fail...

class Foo
{
string s = Bar.s;
public void M1()
{
Console.WriteLine(this.s);
}
}

class Bar
{
internal static string s;
}
class Test
{
static void Main()
{
Foo f1 = new Foo();
f1.M1();
Bar.s = "Hello";
Foo f2 = new Foo();
f2.M1();
}
}

I don't see any exaxmples there of fields explicitly being set to their
default values, e.g.

int i = 0;

or

String s = null;

*That's* what I'm thinking the JIT could eliminate the code for.
 
Jon Skeet said:
But that's not the same situation. It's one thing for an initializer to
take a value from elsewhere - that has to be done dynamically. It
wouldn't be hard for the JIT to realise that initializers were taking
*constant* values which were also the default ones, and just skip that
initialization step.


I'm having second thoughts now. When do statements like

int i = 0; // i is a field, not a local variable

run? For Java, I know that answer: it's after the superclass is fully
constructed, but before the current class's constructor runs. I'm not sure
about C#, though I presume the answer is similar.

Anyway, how hard is it to prove that the superclass constructor doesn't do
anything that might set a field to a non-default value? Certainly there are
cases where it's easy:

1. The class is a direct child of Object., or
2. The superclass constructor is available to the JIT (as is its superclass
constructor, etc. all the way up) and it calls no virtual methods, does not
pass "this" to any methods, (and does no reflection.

Almost anything else leaves some gap, say that a virtual function overidden
in some derived class sets the field, either by calling another virtual
function or by reflection (or by setting it directly, if it's public or
protected rather than private.)

So (as Dennis Moore said, when the poor he was giving to had become
wealthier than the rich he had taken everything from) this is more
complicated than I had thought..
 
Mike Schilling said:
I'm having second thoughts now. When do statements like

int i = 0; // i is a field, not a local variable

run? For Java, I know that answer: it's after the superclass is fully
constructed, but before the current class's constructor runs. I'm not sure
about C#, though I presume the answer is similar.

No, it's not quite. In C#, it occurs before the *base* constructor
runs, which makes life much simpler.

So (as Dennis Moore said, when the poor he was giving to had become
wealthier than the rich he had taken everything from) this is more
complicated than I had thought..

Fortunately not.
 
Jon Skeet said:
But that's not the same situation. It's one thing for an initializer to
take a value from elsewhere - that has to be done dynamically. It
wouldn't be hard for the JIT to realise that initializers were taking
*constant* values which were also the default ones, and just skip that
initialization step.

Jon, that's right, but this is the job for the language compilers - and
that's been taken care of in C# v2.0 (optimized builds!). I for one would
have prefered that C# did not allowed instance variable initializers at all
and only allowed statics to be initialized that way, just like it's been
done in managed C++.

Willy.
 
Back
Top