Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it possible to instantiate a struct without the new keyword?

Why are we not forced to instantiate a struct, like when using a class?

like image 542
Birdman Avatar asked Oct 14 '11 12:10

Birdman


People also ask

How do you instantiate a struct without new?

Like a class, you can create an instance of a struct using the new keyword. You can either invoke the default parameterless constructor, which initializes all fields in the struct to their default values, or you can invoke a custom constructor.

How can struct be instantiated?

When you create a struct object using the New operator, it gets created and the appropriate constructor is called. Unlike classes, structs can be instantiated without using the New operator. If the New operator is not used, the fields remain unassigned and the object cannot be used until all the fields are initialized.

Can we use new keyword with struct?

A struct object can be created with or without the new operator, same as primitive type variables. Above, an object of the Coordinate structure is created using the new keyword.

Can a struct be initialized?

Using designated initializers, a C99 feature which allows you to name members to be initialized, structure members can be initialized in any order, and any (single) member of a union can be initialized.


2 Answers

Why are we not forced to instantiate a struct with "new", like when using a class?

When you "new" a reference type, three things happen. First, the memory manager allocates space from long term storage. Second, a reference to that space is passed to the constructor, which initializes the instance. Third, that reference is passed back to the caller.

When you "new" a value type, three things happen. First, the memory manager allocates space from short term storage. Second, the constructor is passed a reference to the short term storage location. After the constructor runs, the value that was in the short-term storage location is copied to the storage location for the value, wherever that happens to be. Remember, variables of value type store the actual value.

(Note that the compiler is allowed to optimize these three steps into one step if the compiler can determine that doing so never exposes a partially-constructed struct to user code. That is, the compiler can generate code that simply passes a reference to the final storage location to the constructor, thereby saving one allocation and one copy.)

So now we can address your question, which you actually have asked backwards. It would be better to ask:

Why are we forced to allocate a class with "new", instead of simply being able to initialize the fields as with a struct?

You have to allocate a class with "new" because of those three things on the list. You need new memory allocated from the long-term storage and you need to pass a reference to that storage to the constructor. "new" is the operator that knows how to do that.

You don't have to call "new" on a struct because there is no need to allocate the "final" storage; the final storage already exists. The new value is going to go somewhere, and you already have obtained that storage by some other means. Value types do not need a new allocation; all they need is initialization. All you need to do is ensure that the storage is properly initialized, and you can often do that without calling a constructor. Doing so of course means that you run the risk of having a variable of value type that can be observed to be in a partially initialized state by user code.

Summing up: calling a ctor is optional for value types because no new memory needs to be allocated when initializing an instance of a value type and because skipping the constructor call means that you get to skip a short-term allocation and a copy. The price you pay for that performance gain is that user code can see a partially initialized structure.

like image 178
Eric Lippert Avatar answered Sep 20 '22 08:09

Eric Lippert


The why is simply - because the spec says so. The how is a matter of ensuring that the entire block of memory is "definitely assigned", which means: assigning a value to each field of the struct. However, this requires 2 nasty things:

  • public fields (almost always bad)
  • mutable fields (generally bad in a struct)

so in most best-practice cases, you do need to use the new(...) syntax, to invoke the constructor (or to zero-the memory, for the parameterless constructor) for the type correctly.

like image 25
Marc Gravell Avatar answered Sep 20 '22 08:09

Marc Gravell