BoSsYyY
BoSsYyY

Reputation: 563

What does happen when you make a struct without using the new keyword?

What does happen behind the scenes when you make a struct without using the new keyword?

Let's say we have this struct:

struct Person
{
    public int Age;
    public string Name;
}

And In the Main() method I decide to make an instance of it without the new keyword like that:

Person p;

now if I try to access p.Age I will get a compile-time error saying "Use of possibly unassigned field 'Age'" however if I make an instance of the struct like that:

Person p = new Person();

and then I try to access p.Age I will get the value of 0. Now what exactly happens behind the scenes? Does the Runtime initialize these variables for me or the compiler places code that initializes them in the IL after compilation?

Edit: Can anybody also explain this behavior: Code:

struct Person
{
    public string Name { get; set; }

}

If I make instance of struct like that:

Person p;

and I initialize the name manually

p.Name = "SomeRandomName"';

I won't be able to use it. The compiler gives an error "Use of an unassigned local variable p" but If I make instance of the struct with the default (parameterless) constructor there isn't such an error.

Upvotes: 3

Views: 2271

Answers (3)

Paul Karam
Paul Karam

Reputation: 4210

If you go through the small struct documentation, you can quote:

A struct type is a value type that is typically used to encapsulate small groups of related variables, such as the coordinates of a rectangle or the characteristics of an item in an inventory.

Normally, when you declare in your code these value type like:

int i; // By default it's equal to 0
bool b; // by default it's equal to false.

Or a reference type as:

string s; //By default it's null

The struct you have created is a value type, which by default isn't initialized and you can't access its properties. Therefore, you can't declare it as:

Person p;

Then use it directly.
Hence the error you got:

"Use of possibly unassigned field 'Age'"

Because p is still not initialized. This also explains your second part of the question:

I won't be able to use it. The compiler gives an error "Use of an unassigned local variable p" but If I make instance of the struct with the default (parameterless) constructor there isn't such an error.

The same reason you couldn't directly assign p.Name = "something" is because p is still not initialized.

You must create a new instance of the struct as

Person p = New Person(); //or Person p = default(Person);

Now, what happens when you create a new instance of your struct without giving values to the struct properties? Each one of them will hold it's default value. Such as the Age = 0 because it's an int type.

Upvotes: 1

Luaan
Luaan

Reputation: 63742

Members don't have the same rules as locals.

Locals must be explicitly initialised before use. Members are initialised by the runtime to their respective default values.

If you want some more relevant information:

In the internal implementation details (non-contractual!), up to the current MS .NET runtime for Windows objects are allocated in pre-zeroed memory on the heap (when they're on the heap at all, of course). All the default values are "physical" zeroes, so all you need is e.g. "200 consecutive bytes with value 0". In many cases, this is as simple as asking the OS for a pre-zeroed memory page. It's a performance compromise to keep memory safety - you can easily allocate an array of 2000 Person instances by just doing new Person[2000], which just requests 2000 * size of Person bytes with value zero; extremely cheap, while still keeping safe default values. No need to initialise 2000 Person instances, and 2000 int instances and 2000 string instances - they're all zero by default. At the same time, there's no chance you'd get a random value for the string reference that would point to some random place in memory (a very common error in unmanaged code).

The main reason for requiring explicit initialisation of locals is that it prevents stupid programming errors. You should never access an uninitialised value in the first place, and if you need a default value, you should be explicit about it - the default value then gets a meaning, and meanings should be explicit. You'll find that cases where you could use an uninitialised local meaningfully in the first place are pretty rare - you usually either declare the local right where it gets a value, or you need all possible branches to update a pre-declared local anyway. Both make it easier to understand code and avoid silly mistakes.

Upvotes: 3

Dee J. Doena
Dee J. Doena

Reputation: 1843

Every datatype in .NET has a default value. For all reference types it's null. For the special type string it is also null. For all value types it is something akin to zero. For bool it's false because this is the equivalent to zero.

You can observe the same behaviour when you write a class with member fields. After construction all these fields will have a default value even when none was assigned during construction.

The same is also true when you use a struct as a member. Since a struct cannot be null, it will also be initialized and all its members (again) use their default values.

The difference in compiler output is that the compiler cannot determine if you have initialized the member field through any means. But it can determine if you have set the method variable value before reading it. Technically this wouldn't be necessary but since it reduces programming errors (why would you read a variable you have not written?), the compiler error appears.

Upvotes: 1

Related Questions