Today's the big day: Janell (aka, the Queen, the Boss, Miss Mulcahy if
you're nasty) and I get to start moving into our new house!
More pictures soon, but I thought you might enjoy a little Orbital View of the area.
I’ve been engaged in a rather interesting discussion today that arose from questions on a VB.NET mailing list we have over at DevelopMentor. The question boils down to the behavior of code like this:
Sub Main()
Dim this As DateTime
Dim that As DateTime = Nothing
Dim other As DateTime = #12:00:00 AM#
this = Nothing
that = New DateTime(0)
If this = Nothing Then Console.WriteLine("Its nothing.")
If this = that Then Console.WriteLine("Its Zero.")
If this = other Then Console.WriteLine("Its Midnight, 1/1/1 AD.")
Console.ReadLine()
End Sub
What’s the output you expect to see?
If you said “Its nothing,” you’d be correct. Obviously, we just assigned that variable’s value the value of nothing.
If you said “Its zero,” and or “Its Midnight, 1/1/1 AD” you’d be correct. Don’t believe me? Run the code.
So, how is nothing something even if that something is zero? Nothing (in VB.Net’s sense) must be something, not nothing (in the true sense of null), and zero must be something, not nothing (again, in the VB.NET sense) nor nothing (in the true sense of null). Visual Basic.NET actually says that if you set a value type instance to nothing, it actually sets the value of that type to its default. In this case, the default value of a DateType instance is the date and time of midnight, January 1, 1 AD, which just so happens to be the value represented by zero ticks.
So why, other than it makes for fun word games and would be an interesting interview question, should you care about this? Probably the best reason to care is that code like this:
Sub Main()
Dim this As DateTime
Dim that As DateTime
this = Nothing
Console.ReadLine()
End Sub
Generates Intermediate Language code like this (note, this is using Lutz Roeder’s excellent tool Reflector to extract the IL):
.method public static void Main() cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
.maxstack 1
.locals (
[mscorlib]System.DateTime time1,
[mscorlib]System.DateTime time2)
L_0000: nop
L_0001: ldloca.s time2
L_0003: initobj [mscorlib]System.DateTime
L_0009: call string [mscorlib]System.Console::ReadLine()
L_000e: pop
L_000f: nop
L_0010: ret
}
The gremlin here is the “this = Nothing” statement. Most of the time when I see code like this, the developer wrote it not really understanding what setting a value type to nothing actually does. In this specific case, the developer assumed that setting a DateTime to nothing would set the value to some definite but non-comparable (and non-ascertainable) value. But as we’ve just seen, setting a value type instance to nothing really does give it a comparable and ascertainable value. In the IL, our statement “this = Nothing” translates into the L_0001 and L_0003 instructions. However, these instructions are effectively wasteful, since they are simply writing the same values (bitwise) onto the stack that were already there.
So key take-aways from this are:
- 1. Don’t assume that setting a value type to nothing means anything like setting it to null (in the since that it is both non-comparable and non-ascertainable). In fact, its best to assume it is going to be exact opposite. Setting a value type instance nothing really does set it something very much specific and ascertainable – the type’s default value.
- 2. Some value types give you many ways to represent the same value. DateTime is a classic example of this, since it can represent some point-in-time as a number of ticks (a long integer), a date, a time and a date and time. This means that you can do some odd looking comparisons, like comparing time zero to midnight and to the nothing value and actually having a true result.