P.Brian.Mackey
P.Brian.Mackey

Reputation: 44275

New-ing string types

From Pro C#

Referring to "New-ing" Intrinsic data types...

All intrinsic data types support what is known as a default constructor. It allows you to create a variable using the new keyword.

[...] Object references (including strings) are set to null.

In C#, strings do not have a public default constructor. My guess is that due to string's immutability, they have a private default constructor. But, the context here is talking about Object references and string's as a whole while using new.

Because one cannot do

String myString = new String();

So,

String a;

referencing string doesn't result in a "default value". Instead, it's a compiler error to access a.

Though

public class StringContainer
{
    public static string myString { get; set; }
}

Results in a legally accessible string (defaulted to null). This doesn't use new. It performs some kind of magical construction.

What is occurring in the StringContainer scenerio? Because there appears to be no new-able default constructor in string, is this an error in the C# book?

Upvotes: 4

Views: 800

Answers (3)

Eric Lippert
Eric Lippert

Reputation: 660098

All intrinsic data types support what is known as a default constructor. It allows you to create a variable using the new keyword.

There are an impressive number of subtle errors in that statement.

First off, there is no such thing as an "intrinsic" data type; perhaps this term is defined somewhere else in the book?

Second, it would be more accurate to say that all struct types have a public parameterless constructor called the "default" constructor. Some class types also have a public parameterless ctor; if you do not provide any ctor then the C# compiler will automatically generate a public parameterless ctor for you. If you do provide a ctor then the C# compiler will not do this for you.

Third, constructors do not create variables. The author is conflating a bunch of related but different things: the "new" operator, the memory manager, the constructor and the variable, and the created object. Variables are storage locations and are managed by the CLR; they are not created by the "new" operator.

The correct statement is that the "new" operator on a struct causes a variable to be created by the CLR on the temporary storage pool; that variable is then initialized by the memory manager, and then passed to the constructor for more initialization. The value thus created is then copied somewhere else. The "new" operator on a class causes the CLR to create an object on the long-term storage pool, and then pass a reference to that object to the CLR. No "variable" need be involved.

Confusing variables with objects is a very common error; it is valuable to understand the difference.

In C#, strings do not have a public default constructor.

Correct.

My guess is that due to string's immutability, they have a private default constructor.

Good guess, but wrong. There is no private parameterless constructor on string.

[an auto-property or field of type string] results in a legally accessible string (defaulted to null). This doesn't use new. It performs some kind of magical construction.

It does no such thing. A null reference is not a constructed object at all. It's the absence of a constructed object!

You're basically saying that my empty garage contains a "magically constructed" non-existing car. That is an exceedingly weird way to look at an empty garage; an empty garage contains no car at all, not a magically constructed non-existing car.

What is occurring in the StringContainer scenerio?

The containing type contains a compiler-generated field -- a variable -- of type string. Let's suppose the containing type is a struct or class. When the storage for the struct or class is initialized by the memory manager, the memory manager writes a null reference into the storage location associated with the variable.

Finally: I suspect your confusion is because you've gotten the "default constructor" and the "default value of a type" confused. For a struct, they are the same thing:

int x = new int();

and

int x = default(int);

both make an int initialized to zero.

For a class, they do not do the same thing:

Fruit f = new Fruit(); 

makes a new fruit reference and assigns the reference to variable f, whereas:

Fruit f = default(Fruit);

is the same as

Fruit f = null;

No constructor is called.

Upvotes: 18

Joe White
Joe White

Reputation: 97708

All intrinsic data types support what is known as a default constructor. It allows you to create a variable using the new keyword.

I'm not sure what the author means by "intrinsic data types". My best guess is that he actually means "value types" (i.e. types declared with C#'s struct keyword), because value types always have a default constructor, and reference types may not.

So if you have a field whose type is a struct type (e.g. Int32, CancellationToken), then that field will be initialized as if the type's default constructor was called.

In actual implementation, there's probably not an actual call to the type's default constructor -- the memory is just initialized to all zeroes, which is the same thing that would happen if you did call the default constructor. (That's why you can't provide your own parameterless constructor for a value type -- the parameterless constructor always initializes the memory to all zeroes. This greatly simplifies things like new int[10000] -- the compiler doesn't actually have to call new Int32() 10,000 times; it just zeroes out the memory.)

Your question about a string field in a class isn't really related to the author's discussion of "intrinsic data types", because both string and your enclosing class are reference types, not value types. So your class won't have a parameterless-constructor-that-you-can't-override; it will just have normal constructors. But the zeroing-out behavior is still there: when you call a constructor, the new memory block is zeroed out before the constructor code starts to run. Your string field is a reference type, and a zero reference is null.

Upvotes: 5

Joey
Joey

Reputation: 1800

I imagine it is using default(string) which returns null because string is a reference type.

Also, remember that constructors can't return null.

Upvotes: 2

Related Questions