I've read many of the SO questions on the null coalescing ??
operator but none of them seem to address the following specific issue, which concerns neither nullability (here), operator precedence (here and here) nor especially implicit conversion (here, here, here and here). I've also read the .NET docs (more here) and tried to read the offical spec, but sadly all to no avail.
So here goes. The only difference between the following two lines is the use of var
for type inference in the second, versus explicit type Random
in the first, yet the second line gives the error as shown, whereas the first is just fine.
Random x = new Random() ?? (x = new Random()); // ok
var y = new Random() ?? (y = new Random()); // CS0841
// ^-------- error here
CS0841: Cannot use local variable 'y' before it is declared
What is it precisely about the second line that makes the outcome uncertain?
From the hubub I cited above, I learned that the possibility of the left-side of the ??
operator being null
introduces a dependency on the runtime determination of the actual instantiated type of its right-side. Hmm, ok, I guess,... whatever that means? Maybe the amount of alarm generally wafting about the ??
operator on this site should have been some kind of dire warning...
Zeroing-in now, I thought that the whole point of the var
keyword (as very specifically opposed to dynamic
) was that it was not suscceptible to runtime considerations like that, by definition.
In other words, even if we adopt the conservative but perfectly defensible rule of "never peering beyond any assignment =
operator", such that we therefore get no helpful information whatsoever from the right-side of the ??
, then based on the left-side alone, the overall result must be "compatible with" Random
. That is, the result must be Random
or a more specific (derived) type; it cannot be more general. By definition, therefore, shouldn't Random
be the inferred type, for this compile-time use of var
?
As far as I can understand, corrupting var
with runtime considerations summarily defeats its purpose. Isn't that precisely what dynamic
is for? So I guess the questions are:
dynamic
have been implemented without corrupting the purity of static typing?var
just maintain a policy of strict conservatism--always inferring the most-specific type that can be statically inferred--at the same time as the null-coalescing operator is doing whatever it wants to do based on information from the future?It's not a runtime consideration.
The compile time type of a variable declared using var
is the static type of its initializer. The static type of a ??
expression is the common type of the static type of both operands. But the static type of the second operand is the static type of y
, which isn't known. Therefore the static type of the whole initializer is unknown, and deduction fails.
It's true that there exist types for which the initialization would be consistent, but they can't be found using the C# inference rules.