This code will currently not work:
public class Sample
{
public static void Main()
{
//Simple Case.
var list = new List {"A", "B", "C"}; //Zero ambiguity, simple to infer.
//Advanced Case - best generic type argument inference.
var animalsList = new List { new Dog(), new Cat() };
}
}
public abstract class Animal {}
public class Dog : Animal {}
public class Cat : Animal {}
Even the simple case is a big improvement that could be easily achieved (I guess).
PS: should work for Dictionary<,> as well.
I'm afraid there will be no consensus as to what common denominator type should be in this case:
``` C#
class Animal {}
interface ICute {}
interface IExpensive {}
class Dog : Animal, ICute, IExpensive {}
class Cat : Animal, ICute, IExpensive {}
class Dress : ICute, IExpensive {}
new List { new Dog(), new Cat(), new Dress() };
```
Is it object
or ICute
, or IExpensive
?
I believe it can be inferred from the usage of that list. It's a local value after all.
I would have inferred it as object since that is the only type that fits all the arguments. I don't think it should ever infer interfaces at all unless all arguments are explicitly of that interface. In the case of explicit different interfaces there should be a compilation error since it doesn't infer interfaces.
@GeirGrusom - that would certainly be preferable to some complex rules or no type parameter inference at all.
Frankly speaking in most cases all I want is this:
var list = new List {"A", "B", "C"}; //Zero ambiguity, simple to infer.
@dsaf I think it would be welcome for simple cases like the example of
``` C#
var list = new List {"A", "B", "C"};
as this matches the existing semantics of implicitly typed array declarations which are a nice feature.
``` C#
var array = new [] {"A", "B", "C"};
However, as @marhoily comments, there is often not always an obvious common ancestor.
However, this could be addressed if the language supported intersection types.
In that case,
for
``` C#
class Animal {}
interface ICute {}
interface IExpensive {}
class Dog : Animal, ICute, IExpensive {}
class Cat : Animal, ICute, IExpensive {}
class Dress : ICute, IExpensive {}
new List { new Dog(), new Cat(), new Dress() };
The inferred type might sensibly be something like
``` ada
List<ICute with IExpensive>
For example Scala will produce exactly such a synthesized type.
However it can be taken a bit too far in my opinion.
Scala also allows the following:
val xs = List(1, print(2), new MyClass)
for which it infers the type List[Any] which is probably not what one would expect, and may be masking an error as although Int, Unit, and MyClass all inherit indirectly from Any, it does not often make sense to store Unit in a List.
@aluanhaddad I would prefer the simple case support in C#7 to start rather than complete support in C#9.
@aluanhaddad
However, this could be addressed if the language supported intersection types.
How would that be implemented? AFAIK the runtime doesn't support intersection types (except for generic parameters with constraints). Are you suggesting that the runtime should be changed? Or would ICute with IExpensive
be represented by something like Tuple<ICute, IExpensive>
and then the compiler would automatically access Item1
or Item2
as needed?
@svick It wasn't so much my intent to suggest the addition of intersection types, as to provide a hypothetical context in which such type inferencing would make sense, and giving an example of how an existing language determines the type in such a scenario. I used the syntax IA with IB
just as an example of how one might express such a type signature.
However, if such a feature would be implemented it would probably be part of a larger feature proposal to add Traits or Mixins to the language. I believe there are currently several such feature proposals. If Traits could be applied on a per instance basis, as in Scala, then this feature might be added as a way of referring to the type of such a instances.
@dsaf I would welcome the addition of the simple case as well. I know there was a plan at one point to add generic type inference to constructors, I am not sure what the status of that proposal is though. I remember that @gafter referenced it in a discussion on the codeplex site back in October but I cannot seem to find the actual proposal. Generic type inference for constructors would provide the functionality you desire.
@aluanhaddad You are right, I have created a separate issue for the simple case - it doesn't have to be specific to collections I guess #2319.
As far as I can tell, this proposal requires two features to work:
First of all, List
should be resolved to List<T>
as long as there were no other generic/non-generic types in the scope. However, it can be disambiguated with diamond syntax. After that, type argument should be inferred at the first point that it was being used, e.g. Add
method. Then it would be possible to use this feature with static methods as well, just like F#.
Never take interfaces into consideration when inferring types.
Interfaces are form of multiple inheritance and multiple inheritance should always be treated explicitly.
@Opiumtm you may never been working with LINQ and anonymous types, which returns something like IGrouping<<>f__AnonymousType0#1
1[System.Int32]>` and cannot be explicitely provided by user.
Most helpful comment
Never take interfaces into consideration when inferring types.
Interfaces are form of multiple inheritance and multiple inheritance should always be treated explicitly.