简体   繁体   中英

C# type inference (“var”) assignment from '??' null-coalescing operator

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:

  • Is the null-coalescing operator a lone and/or rare exception to my understanding of C# static (ie, compile-time) typing philosophy?
  • If yes, then what are the benefits or tradeoffs between this design vs. what seems to be going on here, namely, deliberately introducing non-determinism to a system of static type inference, and which it did not previously exhibit? Couldn't dynamic have been implemented without corrupting the purity of static typing?
  • Isn't one of the main points of strong-typing to enable compile-time design rigor via actionable feedback to the developer? Why can't 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.

When you use var , the type is figured out at compile time. Therefore, when you write this:

var    y = new Random() ?? (y = new Random()); 

the compiler cannot determine what y 's type is at compile time and thus starts yelling-the decision whether the left side of ?? is null or not, will be determined at runtime.

A better example would be:

public interface IA { void Do(); }
public class A : IA { ... }
public class B : IA { ... }

A a = null;
var something = a ?? new B(); 

What should be the type of something : IA , A or B ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM