Why Can't the C# Constructor Infer Type

Why can't the C# constructor infer type?


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.

UPDATE March 2015

The proposed feature made it close enough to the top of the list for C# 6 to be specified and designed, but was then cut.

For which reason compiler can't infer generic class constructor type?

The last example won't work because there is no implicit type inference for constructors in C#.

Why doesn't C# support implied generic types on class constructors?

Actually, your question isn't bad. I've been toying with a generic programming language for last few years and although I've never come around to actually develop it (and probably never will), I've thought a lot about generic type inference and one of my top priorities has always been to allow the construction of classes without having to specify the generic type.

C# simply lacks the set of rules to make this possible. I think the developers never saw the neccesity to include this. Actually, the following code would be very near to your proposition and solve the problem. All C# needs is an added syntax support.

class Foo<T> {
public Foo(T x) { … }
}

// Notice: non-generic class overload. Possible in C#!
class Foo {
public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); }
}

var x = Foo.ctor(42);

Since this code actually works, we've shown that the problem is not one of semantics but simply one of lacking support. I guess I have to take back my previous posting. ;-)

Troubleshooting: Why doesn't type inference fail here?

C# doesn't support type inference on constructors, although this can often be overcome through the use of a factory class.

See the answer here: Why can't the C# constructor infer type?

Troubleshooting: Why doesn't type inference fail here?

C# doesn't support type inference on constructors, although this can often be overcome through the use of a factory class.

See the answer here: Why can't the C# constructor infer type?

Why can't the compiler infer the type for this select call?


case Enums.SectionTypes.OnlyText:
return new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return new ImageSection((ImageSectionDTO) s);

These two cases return differen types. The compiler isn´t smart enough to check if those types derive from the same base-type so you have to cast them explicitely:

case Enums.SectionTypes.OnlyText:
return (SectionDTO) new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return (SectionDTO) new ImageSection((ImageSectionDTO) s);

Why this isn´t implemented on the compiler? I assume this is because the compiler has to check for many different types. Assume that your two types Foo1 and Foo2 do not directly derive from Bar but from two different ones (Bar1 and Bar2 accordingly) that themselfs inherit from Bar. Now the compiler should check if Foo1 and Foo2 can be assigned to any common base-class which they can not, and also check if they derive from something that HAS a common base-class (Bar). In the end we had to check the whole inheritance-chain until object, not mentioning any interfaces which should also be checked.

class Foo1 : Bar1 {}
class Foo2 : Bar2 {}

class Bar1 : Bar {}
class Bar2 : Bar {}

Why can't C# infer type from this seemingly simple, obvious case


Test(A);

This fails because the only applicable method (Test<T>(Action<T>)) requires type inference, and the type inference algorithm requires that each each argument be of some type or be an anonymous function. (This fact is inferred from the specification of the type inference algorithm (§7.5.2)) The method group A is not of any type (even though it is convertable to an appropriate delegate type), and it is not an anonymous function.

Test<string>(A);

This succeeds, the difference being that type inference is not necessary to bind Test, and method group A is convertable to the required delegate parameter type void Action<string>(string).

Test((string a) => {});

This succeeds, the difference being that the type inference algorithm makes provision for anonymous functions in the first phase (§7.5.2.1). The parameter and return types of the anonymous function are known, so an explicit parameter type inference can be made, and a correspondense is thereby made between the types in the anonymous function (void ?(string)) and the type parameter in the delegate type of the Test method’s parameter (void Action<T>(T)). No algorithm is specified for method groups that would correspond to this algorithm for anonymous functions.

Test((Action<string>)A);

This succeeds, the difference being that the untyped method group parameter A is cast to a type, thereby allowing the type inference of Test to proceed normally with an expression of a particular type as the only argument to the method.

I can think of no reason in theory why overload resolution could not be attempted on the method group A. Then—if a single best binding is found—the method group could be given the same treatment as an anonymous function. This is especially true in cases like this where the method group contains exactly one candidate and it has no type parameters. But the reason it does not work in C#4 appears to be the fact that this feature was not designed and implemented. Given the complexity of this feature, the narowness of its application, and the existance of three easy work-arounds, I am not going to be holding my breath for it!

Generics: Why can't the compiler infer the type arguments in this case?

UPDATE: This answer was written over ten years ago; since then the type inference specification and implementation have been updated several times including changes to how constraints are used during inference. This answer should be considered of historical interest only; consult a recent copy of the C# specification to see how type inference works in current implementations.



I realize that type inference isn't an exact science

I'm not sure I agree. The spec is quite detailed.

I was wondering if there's some fundamental 'rule' I'm missing here

The fundamental rule that you're missing is probably that constraints are not part of the signature. Type inference works off of the signature.

There are in my opinion good reasons for that design decision. However, many people believe that I am morally wrong for believing that there are good reasons for that design decision. If you're interested in reading what feels like several million words on the topic of whether I'm right or wrong, see my article on the subject and the hundred or so comments telling me I'm wrong:

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/constraints-are-not-part-of-the-signature

Is this a shortcoming of the inference process?

Arguably, yes. In my opinion, it is a reasonable choice given competing design requirements. (Those being "do what the user meant" and "give errors when things look ambiguous".)

is my expectation that the compiler should "figure it out" unreasonable in this case?

No. You seem like a reasonable person, and your expectation appears to be based on good reasoning. However, it is entirely possible to have a reasonable expectation that nevertheless is unmet. This would be one of those cases.

Can I change the method's signature in a way that would make it equally functional yet 'inferrable'?

That's going to be difficult, since the generic Dictionary type is not covariant or contravariant in its conversions. The concept you want to capture is not easily expressed in the type system in a manner that affords inference.

If you prefer using languages with more advanced type inference, consider using F#. If you prefer languages that skew towards "do what the user meant" rather than "report errors on ambiguity", consider using VB.



Related Topics



Leave a reply



Submit