Why cant the compiler resolve the resulting type?

c++ compiler
linker error in c example
online c compiler
example of syntax error and logical error
c++ syntax error
syntax error example
compile time error in c
types of compile errors

I have two IEnumerables of different types, both of which derive from a common base class. Now I try to union the enumerables to get an enumerable of the base class. I have to explicitly cast one of the enumerables to the base class for this to work.

I would have guessed that the Compiler would have automatically chosen the closest common base type for the resulting enumerable, but it does not.

Here is an example of that behavior:

namespace ConsoleApp1
{
    public class BaseClass { }
    public class DerivedClass1 : BaseClass { }
    public class DerivedClass2 : BaseClass { }

    class Program
    {
        static void Main(string[] args)
        {
            List<DerivedClass1> list1 = new List<DerivedClass1>();
            List<DerivedClass2> list2 = new List<DerivedClass2>();
            var a = list1.Union(list2); // Compiler Error
            IEnumerable<BaseClass> b = list1.Union(list2); // Compiler Error
            var c = list1.Cast<BaseClass>().Union(list2); // This works
            var d = list1.Union(list2.Cast<BaseClass>()); // This works
            var e = list1.Cast<BaseClass>().Union(list2.Cast<BaseClass>()); // This works, but ReSharper wants to remove one of the casts
        }
    }
}

var c seems to be easy to explain, as the first enumerable is now of type BaseClass, so a union with the second list, which contains elements which are derived from BaseClass also is easy to understand.

var dis not so easy to understand for me, because we start with an enumerable of DerivedClass1 and union that with BaseClass elements. I am surprised that this works. Is it because a union operation is kind of an commutative operation and so it has to work as c also works?

What are the rules the C# compiler uses to resolve types in a , what are the definitive rules on type inference of lambda expressions; what will the compiler infer and what won't it? Implicitly, where the compiler can infer the resulting type, the same way the type of var is inferred. Specialization is done at runtime by the JIT, but as you've already figured, you're reciving the error at compile time, because it's not caller specialized and the compiler can't express the idea of "this method is only called once and when it is, it has the correct type, so it's declared generic but really isn't" in metadata.

Why cant the compiler resolve the resulting type?

That question is based on a false belief; that the compiler is unable to figure out a common type. The compiler could figure that out quite easily, it simply chooses not to, and there is a good reason it for it.

When the compiler reasons about this, it will always use the types involved in the expression. If not, then where should it stop? Everything could be reduced to IEnumerable<object> and make it work, but that would probably be masking an unintended behavior and probably a bug:

//ee is implicitly typed as IEnumerable<object>
var ee = someEnumerableOfString.Union(someEnumerableOfFoo);

A similar thing happens with the ? operator. The compiler wont go looking for a common ancestor, be it a common base type, an interface or a simply object.

And its a good feature because its not always clear what commonality you would want. Imagine the following:

class A: IBar { }
class B: A, IFoo
class C: A, IFoo

var aa = someEnumerableOfB.Union(someEnumerableOfC);

Why should aa be of type IEnumerable<A>? Why not IEnumerable<IFoo>? And why not IEnumerable<IBar>? It could go on forever...

Another important factor to consider, and that could be leading to confusion is, in the following hypothetically legal statement:

IEnumerable<A> aa = someEnumerableOfB.Union(someEnumerableOfC);

One could argue that you are explicitly specifying the commonality you want with IEnumerable<A>.

But that is not how the compiler reasons out types; the compiler will not try to figure out the type of the righthand side based on the type information of the left hand side of the assignment. The way it works is that it will try to figure out the type of the right hand side and if succeeds, then it will see if its assignable to the left hand side. The error you are getting is because it fails in the first step.

Why cant the compiler resolve the resulting type?, Why cant the compiler resolve the resulting type? That question is based on a false belief; that the compiler is unable to figure out a common type. The compiler could figure that out quite easily, it simply chooses not to, and there is a good reason it for it. The class template or generic expects a type as a parameter. This error can be generated as a result of compiler conformance work that was done for Visual Studio 2005: an unspecialized class template can't be used as a template argument in a base class list. To resolve C3203, explicitly add the template type parameter (s) to the template class name when using it as a template parameter in a base class list.

It cant union DerivedClass2 with DerivedClass1, they share a base class but they are not the same type by any means

var c = list1.Cast<BaseClass>().Union(list2); // This works

this will work since now the union is between BaseClass and DerivedClass2 and DerivedClass2 can be converted into BaseClass since baseClass.GetType().IsAssigneableFrom(derivedClass2)

Formal Techniques for Distributed Systems: Joint 11th IFIP WG 6.1 , As an example we can cite the associations that resolve name and type in the compiler source code in a uniform way, and therefore manual intervention is The resulting type graph obtained from the analysis described in this section is  So I’m coding along and all of a sudden, Eclipse (3.4) can’t resolve classes. Classes that are in the same package as the class I’m editing. Classes that are fully qualified in the import statement. Not good. The last thing I had done was add a Spring @Autowired annotation. I saved the file and voila, everything goes to crap.

You basically have D1 : B and D2 : B.

The union of IEnumerable<D1> (or IEnumerable<D2>) and IEnumerable<B> is an instance of IEnumerable<B> (the order being irrelevant).

It's also sound to say that a union of IEnumerable<D1> and IEnumerable<D2> is an instance of IEnumerable<B>. But in this case, the compiler needs to find the common ancestor of D1 and D2, which apparently doesn't bother to do.

F# High Performance, In the long definition, type provider is a design-time component that provides a a type provider must be available at compile time because the resulting type Type resolved is immediately available in the editor when writing code (in the IDE​  We do not expect the iterator type to be different for different type of allocator. The compiler cannot deduce the template parameter of a dependent type. To summarize, the compiler is pretty much unable to ensure that a type-level function is injective (*).

Eight C++ programming mistakes the compiler won't catch, This can result in intermittent problems, which are particularly hard to track down. If the operands are of an integer type, the division operator will drop function inside the constructor of a base class, expecting it to resolve to  In a ? : expression, the compiler finds the common type of the operands (the type of an operand to which the other operand can be converted). But since you have lambda expressions on both sides of the : , there is no type of either operand and therefore there is no common type.

Understanding and fixing compiler and linker errors, How to fix common compiler and linker errors in C++. Although you don't want to ignore them, compiler warnings aren't something severe enough to This also keeps me from having to type the word, which could result in my correctly  Im getting this on production builds which dont use HMR. Turned out to be a result of having two loaders which matched the file. I didn't get what he meant.

Using the GNU Compiler Collection (GCC): Warning Options, Check the code for syntax errors, but don't do anything beyond that. Disabling the error for this warning can result in poorly optimized code and is useful only in the Give a warning when a value of type float is implicitly promoted to double . In other cases they may be benign and could be resolved simply by adding the​  .unwatch() Stops watching for changes. Returns a promise that fulfills when done..resolve() Resolves the compilation result. The promise gets immediately resolved if the compiler has finished or failed.

Comments
  • Great explanation as always! I'm curious what happens when var a = list1.Union<BaseClass>(list2); as well?
  • @S.Akbari: Well, at that point there's no type inference involved, because the type argument is provided explicitly. It works because both List<DerivedClass1> and List<DerivedClass2> are implicitly convertible to IEnumerable<BaseClass>. I won't add this to the answer as the question is about type inference.