I just shoot myself in the foot and would like to know whether there were actual reasons to make this situation possible.
And anyway, this question can stay for the convenience of the future foot shooters.
Suppose we have a nullable value in vb.net:
Dim i as Integer?
We want to assign a value to it, basing on a condition, and using a ternary operator, because it's so neat and stuff:
i = If(condition(), Nothing, 42)
That is, if a condition is true
, employ the nullability, otherwise the value.
At which point the shooting occurs. For no apparent reason VB compiler decides that the common base type for Nothing
and Integer
is Integer
, at which point it silently translates the statement to:
i = If(condition(), 0, 42)
Now, if you were to do this in C#:
i = (condition()) ? null : 42;
You would immediately get a compiler error saying that <null>
doesn't mix well with int
. Which is great, as my foot would have been healthier had I went the C# way this time. And for this to compile, you have to explicitly write:
i = (condition()) ? null : (int?)42;
Now, you can do the same in VB and get the correct null-ness you would expect:
i = If(condition(), Nothing, CType(42, Integer?))
But that requires having your foot shot in the first place. There's no compiler error and there's no warning. That's with Explicit On
and Strict On
.
So my question is, why?
Should I take this as a compiler bug?
Or can someone explain why the compiler behaves this way?
This is because VB's
Nothing
is not a direct equivalent to C#'snull
.For example, in C# this code will not compile:
But this VB.Net code works just fine:
VB.Net's
Nothing
is actually a closer match for C#'sdefault(T)
expression.The ternary operator can only return one type.
In C#, it tries to choose a type based on
null
and42
. Well,null
doesn't have a type, so it decides that the return type of the ternary operator is that of42
; a plain oldint
. Then it complains because you can't return null as a plain oldint
. When you coerce 42 as aint?
, the ternary operator is going to return anint?
, sonull
's valid.Now, I don't know about VB, but quoting from the MSDN,
Assigning Nothing to a variable sets it to the default value for its declared type.
Which, since VB determines that the ternary operator will return an
int
(using the same process C# did),Nothing
is0
. Again, coercing the42
to be anint?
turnsNothing
into the default value ofint?
, which isnull
, as you expected.Nothing
andnull
are not the same thing... from the MSDN:Also
Keep in mind that int? is a nullable type, but it's still a value type, not a reference type.
Try setting it to
DbNull.Value
instead ofNothing
...In a number of cases
Nothing
will get converted to the default value. To useNothing
the same way you would usenull
you need to cast it to the correct nullable type.This is actually now possible in VS2015 (at the very least) by using New Integer?
Ex.:
I am thinking this has something more to do with IF than with Nothing. Consider this code:
Why it is doing this I still don't know, probably a question for the VB team. I don't think it has to do with the Nothing keyword or Nullable.