7

If I have the C# 8 code:

class Foo {}

And later:

#nullable enable
var bar = new Foo();

Then the type of bar is Foo?. This seems clearly incorrect, as a new expression can't return null. Why would bar be a nullable reference? I even looked up the Nullable Reference Type Specification, and found the following:

Expressions that are never null

The null state of the following expression forms is always "not null":

  • ...
  • new expressions (object, delegate, anonymous object and array creation expressions)
  • ...

And also:

Type inference for var

The type inferred for local variables declared with var is informed by the null state of the initializing expression.

var x = E;

If the type of E is a nullable reference type C? and the null state of E is "not null" then the type inferred for x is C. Otherwise, the inferred type is the type of E.

The nullability of the type inferred for x is determined as described above, based on the annotation context of the var, just as if the type had been given explicitly in that position.

So based on everything I can find in the spec, bar in my very simple example should be of type Foo, not type Foo?. What am I missing?

Michael Powell
  • 853
  • 2
  • 9
  • 12
  • 1
    How do you obtain bar's type? – CodeCaster Jul 01 '20 at 21:38
  • Intellisense in VS Code, which is based on the OmniSharp plugin. – Michael Powell Jul 01 '20 at 21:40
  • 1
    Does [this answer](https://stackoverflow.com/a/61939046/491907) help? It has a link to the c# design notes about the usage of `var` with nullable reference types – pinkfloydx33 Jul 01 '20 at 22:59
  • Yes, that does cover it. I don't entirely agree with their reasoning, but at least I can see what it is. You should make an actual answer out of that. – Michael Powell Jul 01 '20 at 23:09
  • @MichaelPowell Seems that the part of the `C# Specification` provided by you in the post contradicts the next [part](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/nullable-reference-types-specification#nullable-implicitly-typed-local-variables). Please, check this [answer](https://stackoverflow.com/a/62274371/12833205). It provides links to github pages where this behaviour was discussed and implemented. – Iliar Turdushev Jul 02 '20 at 02:44
  • Here's the information from LDM notes: https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-12-18.md#var – Julien Couvreur Jul 02 '20 at 05:52
  • @IliarTurdushev It does, though the question comes at the issue in a somewhat more roundabout way, and the "accepted answer" doesn't actually seem to answer it at all. Though your answer to that question does cover it. I searched around pretty extensively looking for a question matching mine, and couldn't find one. There are a lot of ways to phrase it, and it's hard to be sure I've thought of them all. The downvotes on what I thought was a very well researched question are a bit discouraging. – Michael Powell Jul 02 '20 at 08:57
  • @MichaelPowell I didn't downvote. I agree that your question shows good research effort. I only marked the question as a duplicate of another question. – Iliar Turdushev Jul 02 '20 at 09:05
  • The `var` keyword is incredibly useful even when you want a non-nullable type because you can use `var`, copy the inferred type where your IDE shows it, paste it in place of `var`(without the `?` obviously). Also, it seems to me that you can just keep the `var` for local variables since we don't care about the type as much for local variables and your IDE will probably know that it's not null in this case. – Rivenfall Mar 16 '23 at 10:25

1 Answers1

16

If var were to infer its nullability from the expression, then in many instances you would not be able to assign a null to it later on. For example, var s = "";. There was a discussion to allow var? to express "the nullable version of the type", but it had several issues. Would the regular var be restricted to infer a non-nullable type?

If yes, then (1) we're creating adoption pain as users need to add more ? annotations, (2) we have an inconsistent nullability with var pattern which had already shipped, (3) there are some questions with nullable value types (int?). If no, then the intent of the code would not be very clear. var? would clearly indicate a nullable type, but var would be a mixed bag of nullable and non-nullable.

The decision to infer a nullable type for var was recorded in the LDM notes from 2019-12-18.

Julien Couvreur
  • 4,473
  • 1
  • 30
  • 40
  • 2
    Good answer. I'm really not in agreement with this logic, but I at least see where it's coming from. – Michael Powell Jul 02 '20 at 08:51
  • 4
    So if you want to declare non nullable references (and that occurs a lot more often than nullable), you need to use explicit types (var! could have been an option, no?)… I don’t see where is the gain to not be able to use implicit declarations anymore… – Yet Another Code Maker Aug 11 '21 at 14:38
  • Seeing `var!` I would immediately think "This type is nullable, but we're ignoring that case here." – Chris Jensen Nov 25 '22 at 07:56
  • @ChrisJensen I guess you're thinking about "!" as the null-forgiving operator. Back to the initial question: it seems the compiler or IDE sometimes knows that a var is not null even if its type is nullable, so is it a problem that the type is nullable? – Rivenfall Mar 16 '23 at 09:57