1

I've been trying to understand the implications of nullable reference types for a while now, but I'm still confused. My understanding is that, in a nullable context, you're not supposed to be able to do this:

TestClass nonNullable = null;
public class TestClass { }

I thought you're supposed to need to declare a reference type as nullable to be able to assign it a value of null in a nullable context, like this:

TestClass? nullable = null;

When I compile the first block of code in net5.0 or net6.0 with the Nullable node in the project file set to "enabled", all I get is a compiler warning CS8600. Other than that, everything seems to work the same. However, I understand that nullable reference types are a massive breaking change vis-a-vis older libraries. Why? I've read the Microsoft API reference on this topic: Nullable reference types, as well as chapters in two books. The behavior I'm observing seems to violate Microsoft's specification. Either I'm stupid, the explanations are inaccurate/unclear, or maybe both of these.

  • 1
    RE: "*I thought you're supposed to need to declare a reference type as nullable to be able to assign it a value of null*" . It's *value* types that you have to explicitly enable for nulls like this. Reference types are implicitly nullable (and can be explicitly made non-nullable? Not sure,if this feature is released yet or not). – RBarryYoung Mar 05 '22 at 17:56
  • Reference types (which include `string`, classes) can **always** be assigned to `null` without having `?` on the type definition. Value types (int, float, double, structs, ...) cannot by default. But personally I wouldn't know the added value of using `string?` over `string` – Pieterjan Mar 05 '22 at 17:57
  • 2
    Above comments aren't entirely correct. It depends on whether nullable annotation context is enabled or not https://learn.microsoft.com/en-us/dotnet/csharp/nullable-migration-strategies – Eric J. Mar 05 '22 at 18:06
  • 1
    @Pieterjan: Well, you say they "can always be assigned to null" - that's not the case if you treat nullable warnings as errors. – Jon Skeet Mar 05 '22 at 18:31
  • 2
    @RBarryYoung: Nullable reference types were included in C# 8, released in September 2019. – Jon Skeet Mar 05 '22 at 18:32
  • 1
    @JonSkeet Thanks, I retired 2 years ago and am not completely up-to-date. (But I finally got to have a conversation with Jon Skeet, so my life is now complete! :-) ) – RBarryYoung Mar 05 '22 at 18:44
  • 1
    It means we're all going to get very familiar with the [null object pattern](https://sourcemaking.com/design_patterns/null_object). – radarbob Mar 05 '22 at 18:51
  • Thanks, everybody. So, from what I can tell, turning on null reference types doesn't actually result in anything more than some compiler warnings unless you configure WarningsAsErrors. I'm not sure I understand why nullable reference types are a breaking change, then. Oh well. Life goes on... – Erik Midtskogen Mar 05 '22 at 19:34

1 Answers1

1

Yes, reference variables in any nullable context can be assigned a null value.

"Nullable" and "non-nullable" reference variables are perhaps misleading terms here, because they only indicate whether the compiler should generate warnings for a given variable.

It's also a bit confusing that the context itself is called "nullable" and that enabling it makes reference variables non-nullable in that context, unless you specify otherwise.

TLDR: enable some version of the nullable context feature to generate related warnings at compile time - that's all it does.

As a side note, if you actually want to block your builds based on those warnings, you'll need to take additional steps. See this related answer: https://stackoverflow.com/a/62116924/3743418

AjimOthy
  • 701
  • 5
  • 13
  • OK. Thank you. The behavior you describe is what I am observing in practice. I don't know why the specification explicitly states that "The variable must be initialized to a non-null value." and "The variable can never be assigned the value null." and in the same paragraph is states that the compiler enforces this. Nor do I understand why nullable reference types are some sort of major breaking change. Given what little value there is to gain from this feature (i.e. relief from doing a few null checks) it seems that its implementation and documentation is a confusing mess. – Erik Midtskogen Mar 05 '22 at 19:24
  • @ErikMidtskogen I'll agree that the doc is pretty hard to follow. The section you quoted seems to be trying to explain what the programmer is saying about a variable based on their use of the feature, not what the compiler will enforce. – AjimOthy Mar 06 '22 at 05:29