tags:

views:

3483

answers:

8

In .NET a value type (C# struct) can't have a constructor with no parameters. According to this post this is mandated by the CLI spec. What happes is that for every value-type a default constructor is created (by the compiler?) which initialized all members to zero (or null).

Does anyone know why it is disallowed to define such a default constructor?

One trivial use is for rational numbers

public struct Rational {
    private long numerator;
    private long denominator;

    public Rational(long num, long denom)
    { /* Todo: Find GCD etc. */ }

    public Rational(long num)
    {
        numerator = num;
        denominator = 1;
    }

    public Rational() // This is not allowed
    {
        numerator = 0;
        denominator = 1;
    }
}

Using current C# a default Rational is 0/0 which is not so cool.

P.S. Will default parameters help solve this for C#4.0 or will the CLR defined default constructor be called?


Edit: Jon Skeet answered:

To use your example, what would you want to happen when someone did:

 Rational[] fractions = new Rational[1000];

Should it run through your constructor 1000 times?

Sure it should, that's why I wrote the default constructor in the first place, the CLR should use the default zeroing constructor when no explicit default ctor is defined, that way you only pay for what you use. Then if I want a container of 1000 non default Rationals (and want to optimize away the 1000 constructions) I will use a List<Rational> rather than an array.

This reason, in my mind, is not strong enough to prevent definition of a default constructor.

+33  A: 

EDIT: I've edited the answer below due to Grauenwolf's insight into the CLR.

The CLR allows value types to have parameterless constructors, but C# doesn't. I believe this is because it would introduce an expectation that the constructor would be called when it wouldn't. For instance, consider this:

MyStruct[] foo = new MyStruct[1000];

The CLR is able to do this very efficiently just by allocating the appropriate memory and zeroing it all out. If it had to run the MyStruct constructor 1000 times, that would be a lot less efficient. (In fact, it doesn't - if you do have a parameterless constructor, it doesn't get run when you create an array, or when you have an uninitialized instance variable.)

The basic rule in C# is "the default value for any type can't rely on any initialization". Now they could have allowed parameterless constructors to be defined, but then not required that constructor to be executed in all cases - but that would have led to more confusion. (Or at least, so I believe the argument goes.)

EDIT: To use your example, what would you want to happen when someone did:

Rational[] fractions = new Rational[1000];

Should it run through your constructor 1000 times?

  • If not, we end up with 1000 invalid rationals
  • If it does, then we've potentially wasted a load of work if we're about to fill in the array with real values.

EDIT: (Answering a bit more of the question) The parameterless constructor isn't created by the compiler. Value types don't have to have constructors as far as the CLR is concerned - although it turns out it can if you write it in IL. When you write "new Guid()" in C# that emits different IL to what you get if you call a normal constructor. See this SO question for a bit more on that aspect.

I suspect that there aren't any value types in the framework with parameterless constructors. No doubt NDepend could tell me if I asked it nicely enough... The fact that C# prohibits it is a big enough hint for me to think it's probably a bad idea.

Jon Skeet
Shorter explanation: In C++, struct and class were just two sides of the same coin. The only real difference is one was public by default and the other was private. In .Net, there is a much greater difference between a struct and a class, and it's important to understand it.
Joel Coehoorn
@Joel: That doesn't really explain this particular restriction though, does it?
Jon Skeet
The CLR does allow value types to have parameterless constructors. And yes, it will run it for each and every element in an array. C# thinks this is a bad idea and doesn't allow it, but you could write a .NET language that does.
Jonathan Allen
@Grauenwolf: I've managed to get a value type with a parameterless constructor to compile with ilasm, but the constructor isn't being run when I initialize an array. Is there anything special I'd need to put in the IL other than taking out the parameter from a parameterful constructor (cont)
Jon Skeet
(That's how I got the IL in the first place - a C# struct with a parameterful constructor.) I'll edit my answer to explain the bit we've got to so far...
Jon Skeet
My information is based on "Framework Design Guidelines" 2nd edition. Upon rereading it, I think I may be wrong about it running the constructor for every slot in the array.
Jonathan Allen
That would certainly explain it :) I'll edit the answer. Thanks so much for correcting me though - that's a really good catch!
Jon Skeet
A: 

Do structs allow default member value assignments? e.g.

private long denominator = 1;
devio
Is that rhetorical? Because no: you can't.
Marc Gravell
it wasn't, and I never tried it. thx ;)
devio
+7  A: 

Shorter explanation:

In C++, struct and class were just two sides of the same coin. The only real difference is one was public by default and the other was private.

In .Net, there is a much greater difference between a struct and a class. The main thing is that struct provides value-type semantics, while class provides reference-type semantics. When you start thinking about the implications of this change, other changes start to make more sense as well, including the constructor behavior you describe.

Joel Coehoorn
You'll have to be a bit more explicit about how this is implied by the value vs. reference type split I don't get it...
Motti
Value types have a default value- they are not null, even if you don't define a constructor. While at first glance this doesn't preclude also defining a default constructor, the framework using this feature internal to make certain assumptions about structs.
Joel Coehoorn
one wonders why other constructors *are* allowed then
annakata
+6  A: 

A struct is a value type and a value type must have a default value as soon as it is declared.

MyClass m;
MyStruct m2;

If you declare two fields as above without instantiating either, then break the debugger, m will be null but m2 will not. Given this, a parameterless contrsuctor would make no sense, in fact all any constructor on a struct does is assign values, the thing itself already exists just by declaring it. Indeed m2 could quite happily be used in the above example and have its methods called, if any, and its fields and properties manipulated!

Not sure why someone voted you down. You appear to be the most correct answer on here.
pipTheGeek
The behaviour in C++ is that if a type has a default constructor then that is used when such an object is created without an explicit constructor. This could have been used in C# to initialize m2 with the default constructor which is why this answer isn't helpful.
Motti
I'm not really sure what you're looking for in an answer.I don't believe there is an overriding technical limitation, I believe it was a judgement call, personally I think a correct one. I wouldn't want my structs calling their own constructor when declared.
But you can't write special code for m2 = new MyStruct(); can you?
Martinho Fernandes
onester: if you don't want the structs calling their own constructor when declared, then don't define such a default constructor! :) that's Motti's saying
Stefan Monov
A: 

Just special-case it. If you see a numerator of 0 and a denominator of 0, pretend like it has the values you really want.

Jonathan Allen
Me personally wouldn't like my classes/structs to have this kind of behaviour. Failing silently (or recovering in the way the dev guesses is best for you) is the road to uncaught mistakes.
borisCallens
+1  A: 

You can't define a default constructor because you are using C#.

Structs can have default constructors in .NET, though I don't know of any specific language that supports it.

Jonathan Allen
+1  A: 

You can make a static property that initializes and returns a default "rational" number:

public static Rational One { get { return new Rational(0, 1); } }

And use it like:

var rat = Rational.One;
+2  A: 

Bit late to this, but I think it is a serious flaw.

I want to 'hide' the default parameterless constructor, so developers get a design-time error if they try to use it.

All other 'solutions' seem to be runtime based.

Pp