4

The Nullable<T> type is defined as a struct. In .Net, you can't assign null to a struct because structs are value types that cannot be represented with null (with the exception of Nullable<T>).

int i = null; // won't compile - we all know this
int? i = null; // will compile, and I'm glad it does, and it should compile, but why?

How did Nullable<T> become an exception to the rule "You can't assign null to a value type?" The decompiled code for Nullable<T> offers no insights as of to how this happens.

Dan
  • 9,717
  • 4
  • 47
  • 65
  • possible duplicate of [how are nullable types implemented under the hood in .net?](http://stackoverflow.com/questions/2503811/how-are-nullable-types-implemented-under-the-hood-in-net) – Sriram Sakthivel Sep 03 '13 at 21:26

1 Answers1

14

How did Nullable<T> become an exception to the rule "You can't assign null to a value type?"

By changing the language, basically. The null literal went from being "a null reference" to "the null value of the relevant type".

At execution time, "the null value" for a nullable value type is a value where the HasValue property returns false. So this:

int? x = null;

is equivalent to:

int? x = new int?();

It's worth separating the framework parts of Nullable<T> from the language and CLR aspects. In fact, the CLR itself doesn't need to know much about nullable value types - as far as I'm aware, the only important aspect is that the null value of a nullable value type is boxed to a null reference, and you can unbox a null reference to the null value of any nullable value type. Even that was only introduced just before .NET 2.0's final release.

The language support mostly consists of:

  • Syntactic sugar in the form of ? so int? is equivalent to Nullable<int>
  • Lifted operators
  • The changed meaning of null
  • The null-coalescing operator (??) - which isn't restricted to nullable value types
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    @Dan: If you want lots more detail, I dedicate a whole chapter to nullable value types in C# in Depth :) – Jon Skeet Sep 03 '13 at 21:29
  • @JonSkeet So what would it take to make `int i = null;` equivalent to `int i = new int();`? – Dan Sep 03 '13 at 21:40
  • I suppose runtime will just set `HasValue` property to false when we set `int i = null;` Am I right @Jon – Sriram Sakthivel Sep 03 '13 at 21:49
  • @Dan: It would take a new C# compiler, basically :) – Jon Skeet Sep 03 '13 at 21:53
  • @SriramSakthivel: It doesn't need to set it to false; that's the default value for the type, which is important for arrays etc. Basically there's a `bool` field inside the type. – Jon Skeet Sep 03 '13 at 21:54
  • @JonSkeet Yep, I already knew about it. What if when `i` already has value now we over write it with `null`? will that set the boolean to false or create new nullable? – Sriram Sakthivel Sep 03 '13 at 21:57
  • @SriramSakthivel: It will completely replace the old value with the new value (a pair of `hasValue=null`, `value=0`). This is perfectly normal struct behaviour. – Jon Skeet Sep 04 '13 at 05:43
  • @Jon am really confused at the moment on eric's answer [here](http://stackoverflow.com/a/3049653/2530848). Eric says nullabletypes aren't atomic(I agree) other thread can read a partially value. I know this cannot happen for reference types if we create `new` object since constructor gets executed first and then only it gets assigned to variable. but how this is possible for value types? will it be stored in a variable first and then initialized? – Sriram Sakthivel Sep 04 '13 at 07:14
  • @SriramSakthivel: No, the point is that the amount of data being written may be more than the processor guarantees can be atomically transferred - just like writes of `double` and `long` aren't guaranteed to be atomic. – Jon Skeet Sep 04 '13 at 07:42
  • So does that means another thread can read partially written value? being a immutable struct can other thread read its value partially written? Sorry if am taking up your time – Sriram Sakthivel Sep 04 '13 at 07:49
  • @SriramSakthivel: Yes. Again, this is the same as with normal value types. It's just a matter of not being able to guarantee that a large "chunk" of data writing will be performed atomically. – Jon Skeet Sep 04 '13 at 07:53
  • Thanks Jon, one more thing to confirm will this happen with immutable reference types. I believe no.? am I right? just to confirm with you – Sriram Sakthivel Sep 04 '13 at 07:59
  • @SriramSakthivel: No, because then you'd only be copying a *reference* from place to place, and the reference writes are guaranteed to be atomic. – Jon Skeet Sep 04 '13 at 08:07