views:

365

answers:

4

EDIT: updated the question after PostMan pointed out the error on my part

Just out of curiosity, does anybody know why type inference is not supported for constructor the way they are for generic methods? i.e.

public class MyType<T>
{
   private readonly T field;
   public MyType(T value) { field = value; }
}

var obj = new MyType(42); // why can't type inference work out that I want a MyType<int>?

though you could get around this with a factory class

public class MyTypeFactory
{
   public static MyType<T> Create<T>(T value)
   {
      return new MyType<T>(value);
   }
}
var myObj = MyTypeFactory.Create(42);

Is there a practical or philosophical reason why the constructor can't support type inference?

+12  A: 
public class MyType<T> 
{ 
   private readonly T field; 
   public MyType(T value) { field = value; } 
} 

they can, there is no need to tell the constructor 'what T is' again, seeing as you have already done that in the class decleration.

also your factory is incorrect, you need to have public class MyTypeFactory<T> not just public class MyTypeFactory - unless you declare the factory inside the MyType class

Edit for update:

Well, is 42 a long, a short, an int, or something else?

Let's say you have the following

class Base
{
   public virtual void DoStuff() { Console.WriteLine("Base"); }
}

class Foo : Base
{
   public override void DoStuff() { Console.WriteLine("Foo");  }
}

Then you did this

var c = new Foo();

var myType = new MyType(c);

Would you expect foo to be used, or base? We need to tell the compiler what to use in place of T

When you really wanted to on type base

Hence the

var myType = new MyType<Base>(c);
PostMan
good point, I meant to say why can't the compiler infer the type using the constructor, updating my question. the factory doesn't have to be generic though
theburningmonk
See my edit, if the factory is created inside the MyType Class it knows what T is, but if it's not, you will need T
PostMan
The compiler can not infer the type because there could me multiple constructors. To augment your example, how would the compiler know which constructor to call when `MyType(double)` is present?
Steve Guidi
@PostMan - but in the Create method the compiler can simply infer that T is int
theburningmonk
@theburningmonk it can't if the MyTypeFactory is not declared inside MyType class 'Cannot resolve symbol 'T''
PostMan
@PostMan - stupid me, that should've read Create<T>!
theburningmonk
A: 

The constructor needs to have the same generic specification as the class itself. Otherwise it would be impossible to know if the int in your example would relate to the class or to the constructor.

var obj = new MyType<int>(42);

Would that be class MyType<T> with constructor MyType(int) or class MyType with constructor MyType<T>(T)?

Albin Sunnanbo
This ambiguity can appear also with normal generic methods.
Dykam
It would not be *impossible* to know in most cases. In cases where it could not be unambiguously determined which was intended then we could give an error. This is the same as any other overload resolution problem; if insufficient information is supplied then we simply give an error.
Eric Lippert
+12  A: 

Is there a philosophical reason why the constructor can't support type inference?

No. When you have

new Foo(bar)

then we could identify all types called Foo in scope regardless of generic arity, and then do overload resolution on each using a modified method type inference algorithm. We'd then have to create a 'betterness' algorithm that determines which of two applicable constructors in two types that have the same name but different generic arity is the better constructor. In order to maintain backwards compatibility a ctor on a non-generic type must always win.

Is there a practical reason why the constructor can't support type inference?

Yes. Even if the benefit of the feature outweighs its costs -- which are considerable -- that's not sufficient to have a feature implemented. Not only does the feature have to be a net win, it has to be a large net win compared to all the other possible features we could be investing in. It also has to be better than spending that time and effort on bug fixing, performance work, and other possible areas that we could put that effort. And ideally it has to fit in well to whatever the "theme" is of the release.

Furthermore, as you correctly note, you can get the benefits of this feature without actually having the feature itself, by using a factory pattern. The existence of easy workarounds makes it less likely that a feature will ever be implemented.

This feature has been on the list of possible features for a long time now. It's never been anywhere near high enough on the list to actually get implemented.

Eric Lippert
It's still a bit odd and inconsistent, IMO the language benefits of features being implemented consistently. But that's just my opinion.
Dykam
Ha, not going to get a more accurate answer than this. Thanks Eric for explaining the whole story. :)
Kirk Woll
@Dykam. You are correct; consistency with other features is desirable, but it is far from the only desirable design consideration. Consistency is nice to have; we try to avoid unnecessary inconsistencies. But consistency with other features is very low on the list compared with other design criteria such as cost.
Eric Lippert
A: 

The main reason generic type inference can't work on constructors like you wish is because the class "MyType" doesn't even exist when all you've declared is "MyType<T>". Remember it is legal to have both:

public class MyType<T> {
}

and

public class MyType {
}

Both would be legal. How would you disambiguate your syntax if you did in fact declare both, and both of them declared a conflicting constructor.

Kirk Woll