21

In C# generics, we can declare a constraint for a type parameter T to have a default constructor, by saying where T : new(). However, no other kinds of constraints like this are valid - new(string) for example, etc.

From a language design and/or implementation perspective, what is the reason for this?

Is there something in the way constructors work or in the way the type system is implemented that forbids this (or at least makes it harder)? If so, what is it? I recall reading somewhere that default(T) actually compiles to new T() for T : struct. Is it related to this, maybe?

Or is it simply a design decision made in order to avoid making the language too complicated?

4
  • new(string) is not a default constructor constraint. Your question is tantamount to saying "Why aren't there constraints that require specific constructor signatures?" Very likely because such a constraint would not be particularly useful. Apr 22, 2014 at 22:22
  • 3
    @RobertHarvey Yes, it is exactly what I'm saying. I'm essentially asking whether there's something that makes default constructors special implementation-wise or if it was just an arbitrary choice to include this and not the other. Apr 22, 2014 at 22:27
  • Default constructors are useful in certain specific, and important, ways. For example, they make a type readily serializable. Apr 22, 2014 at 22:30
  • 7
    Specific ctor signatures could be useful. For example, if your type variable is constrained to be of Collection<T> with a ctor of T(Collection<T>), you know you can construct new collections given another. Whether that usefulness is worth the extra complexity, though, is a question.
    – Phoshi
    Apr 23, 2014 at 8:20

2 Answers 2

6

For an authoritative answer, I would refer you to Eric Lippert's answer to that question on StackOverflow a few years ago, a snippet of which is briefly quoted below.

However, in this specific case I can certainly give you some reasons why I would push back on the feature if it came up in a design meeting as a possible feature for a future version of the language.

...

I say that we should either do the whole feature or don't do it at all. If it is important to be able to restrict types to have particular constructors, then let's do the whole feature and restrict types on the basis of members in general and not just constructors.

7
  • 2
    That quote, taken out of context, is very misleading. It suggests that Eric thought that Microsoft should have "gone all the way," which is not his position at all. He is, in fact, squarely against the proposed feature. Apr 22, 2014 at 22:29
  • 1
    Thanks, this is does answer my question partially: Near the end of his answer, Eric Lippert mentions that it's a limitation of the IL and including this feature would require an addition to the IL. It'd be perfect if you could provide a source on what IL is generated for the part that is implemented - that is, generically calling a default constructor. Apr 22, 2014 at 22:33
  • @TheodorosChatzigiannakis: Why don't you fire up Telerik's Decompiler and find out for yourself? Apr 22, 2014 at 22:37
  • 2
    @RobertHarvey I don't think it suggests a position for him at all, but I've included an additional quote to emphasize his position. Apr 22, 2014 at 22:37
  • 1
    Hmm, F# has more advance ways to constrain a type, like checking as compile time if a class has an operator. Perhaps, F# needs a more powerful constraint system than C# due to its very strict type checking. Nonetheless, this language is able to implement a advanced ways to constain class on .Net Framework. Apr 23, 2014 at 4:28
16

Decompiling (as per Robert Harvey's suggestion) yielded the following, for anyone interested. This method:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Apparently, when compiled, becomes this:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • If T is a value type, new() becomes default(T).
  • If T is a reference type, new() works using reflection. Activator.CreateInstance() internally calls RuntimeType.CreateInstanceDefaultCtor().

So there it is - internally, default constructors really are special to C# in relation to the CLR. Giving other constructors the same treatment would have been costly, even if there are some valid use cases for more complicated constraints in generics.

2
  • 4
    Interesting. Why the duplicate call to default(T) for value types? Apr 23, 2014 at 11:51
  • 2
    @AvnerShahar-Kashtan I don't know. It may be an artifact of the compilation/decompilation process, like the t variable (which could be replaced by nested return statements). Apr 23, 2014 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.