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?

  • `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. – Robert Harvey Apr 22 '14 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. – Theodoros Chatzigiannakis Apr 22 '14 at 22:27
  • Default constructors are useful in certain specific, and important, ways. For example, they make a type readily serializable. – Robert Harvey Apr 22 '14 at 22:30
  • 7
    Specific ctor signatures could be useful. For example, if your type variable is constrained to be of Collection with a ctor of T(Collection), you know you can construct new collections given another. Whether that usefulness is worth the extra complexity, though, is a question. – Phoshi Apr 23 '14 at 08:20

2 Answers2

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.

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.

Chris Hannon
  • 184
  • 4
  • 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. – Robert Harvey Apr 22 '14 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. – Theodoros Chatzigiannakis Apr 22 '14 at 22:33
  • @TheodorosChatzigiannakis: Why don't you fire up [Telerik's Decompiler](http://www.telerik.com/products/decompiler.aspx) and find out for yourself? – Robert Harvey Apr 22 '14 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. – Chris Hannon Apr 22 '14 at 22:37
  • The entirety of his post makes his position pretty clear: it is technically infeasible for dubious benefit. Read the last two paragraphs of his answer for an actual summary of his position. – Robert Harvey Apr 22 '14 at 22:38
  • 1
    Hmm, F# has more [advance ways to constrain a type](http://msdn.microsoft.com/en-us/library/dd233203.aspx), 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. – OnesimusUnbound Apr 23 '14 at 04:28
  • @RobertHarvey: I don't think it would be technically infeasible if there were a rule that types with certain features would be "deemed" to implement an interface with a specially-constructed name (much as T[] are "deemed" to implement IList for all U such that T:U), and no types should implement an interface with such a name unless they have the features in question. Such a system might not be robust against mischievously-constructed types, but would offer accurate compile-time checking except with types that *went out of their way* to defeat it. – supercat Mar 17 '15 at 21:18