1

Consider the following code snippet to follow my mind chronologically. The commented statements cannot be compiled.

    var data1 = new int[3] { 1, 2, 3 };
    var data2 = new int[] { 1, 2, 3 };

    var data3 = new[] { 1, 2, 3 };
    var data4 = new[] { 1, 2, 3.0f };

The simplification done for data3 and data4 is understandable.

    int[] data5 = { 1, 2, 3 };
    //var data6 = { 1, 2, 3 };

Unable to infer the declaration for data6 is understandable.

    var data7 = new int[] { };
    //var data8 = new [] { }; 
    //int[] data9 = new [] { };

Unable to infer the declaration for data8 is also understandable.

What I don't understand is why data9 which is more informative cannot be compiled while data10 that is less informative can be compiled.

    int[] data10 = { };
    //var data11 = { };

Declaring data11 that cannot be compiled is also understandable.

Cœur
  • 37,241
  • 25
  • 195
  • 267
kiss my armpit
  • 3,413
  • 1
  • 27
  • 50
  • 1
    Without being as precise as Eric Lippert would, I think it's fair to say that *inference occurs on the right-hand side of that assignment, not the left-hand side.* In other words, you need a target `var` in which to put the inferred item; specifying the target type is not going to do it, if there's not enough information on the right-hand side of the equals sign to figure out what the expression type is. – Robert Harvey Jun 09 '14 at 19:50
  • 1
    @RobertHarvey, I think the question is about `int[] data9 = new [] { };` vs `int[] data10 = { };`, second one is allowed, but not the first one. – Habib Jun 09 '14 at 19:51
  • 2
    @Habib: `int[] data9 = new [] { };` looks like a type error to me. `new [] { };` is not an `int[]`. The type of the expression on the right-hand side of the equals must be compatible with the declared type on the left-hand side. Again, inference is not occurring on the left-hand side of the equals. – Robert Harvey Jun 09 '14 at 19:52
  • `int[] data9 = { };` this would work but adding new will not compile `var data7 = new int[] { };` compiles because compiler infers type to be of `Int32` – MethodMan Jun 09 '14 at 19:54
  • @RobertHarvey, with or without the space, the compiler error is "No best type found for implicitly-typed array." – Anthony Pegram Jun 09 '14 at 19:55
  • @AnthonyPegram: Yes, that's what I said. – Robert Harvey Jun 09 '14 at 19:55
  • @DJKRAZE, he already knows that work work. See: `int[] data10` from the question text. @RobertHarvey, your comment text changed since I saw it. It was originally much vaguer (syntax error, or some such thing). – Anthony Pegram Jun 09 '14 at 19:56
  • `var data11 = new { };` compiles as anonymous type – MethodMan Jun 09 '14 at 19:57
  • @RobertHarvey, I am totally familiar with what he's trying to do I know when to use and when not to use especially when I have fellow developers whom think that code won't compile because one does not initialize an array size for example that's why `string[] mystring = { };` will compile and initially have mystring[0] will have a length of `0` if this code were used for example and it's easier to dynamically size it if one were to fill / populate it from a List for example – MethodMan Jun 09 '14 at 20:03
  • @DJKRAZE: Are you responding to the right person? – Robert Harvey Jun 09 '14 at 20:21
  • sorry @RobertHarvey I meant that for Anthony Pegram no biggie – MethodMan Jun 09 '14 at 21:09

2 Answers2

2

C# is of type of language that cannot infer types from context. It means that it can extract types only from the expression outside, not vice versa.

In other words, the phenomenon you have shown is identical to the fact that the compiler cannot choose the correct overload in the following case:

int foo();
string foo();

string x = foo();

However it can choose the correct overload in the following case:

void bar(int x);
void bar(string x);

string x;
bar(x);

Edit: Servy commented that lambda expression is an exception for that rule. For example:

var a = new Func<int, bool>(a => a == 1);

the compiler cannot infer the type of "a => a == 1" without inferring it from the context.

MaMazav
  • 1,773
  • 3
  • 19
  • 33
  • I think I see what you're saying here, but the way you're saying it is not at all clear. – Robert Harvey Jun 09 '14 at 19:57
  • 1
    Your first statement isn't quite correct. They try hard to avoid inferring types from context wherever possible, but they haven't succeeded entirely in that regard. The type of lambdas is dependent on their context. `() => false;` has no type, you need to assign it to something like an `Action` for the compiler to deduce its type. – Servy Jun 09 '14 at 19:59
2

The cases where there is a new keyword present, are usual expressions that can be used by themselves in any context where an expression is required. You use them for declarations with assignment, but they can be used in other contexts, for example:

return new[] { 3 };

or:

Call(new[] { 3 });

and so on. In these new array expressions, the type must be clear from the expression itself. This is required even when there is a variable declaration on the left.

The case data9 therefore, with int[] data9 = new [] { }; is illegal because the expression new[] { } is illegal. It is somewhat like:

object related9 = someBoolean ? "Yes" : new Exception();

which is also illegal because the expression someBoolean ? "Yes" : new Exception() is illegal in itself, with incompatible types. There is a declaration of type object, but that does not make the right-hand side legal.


The examples data5 and data10 show a completely unrelated syntax for array variable declaration.

int[] data5 = { 1, 2, 3 };

Here the right-hand side of the = operator is not an expression in itself. This syntax requires a declaration with explicit type on the left of the = sign (so data6 is not OK). This syntax is related to object initializers and collection initializers and was introduced in the C# language together with them, whereas the new[] { ... } syntax is a bit older.


You should see this answer by Lippert, then read the official C# Language Specification.

Community
  • 1
  • 1
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181