Ternary Operator Vb VS C#: Why Resolves Nothing to Zero

Ternary operator VB vs C#: why resolves Nothing to zero?

This is because VB's Nothing is not a direct equivalent to C#'s null.

For example, in C# this code will not compile:

int i = null;

But this VB.Net code works just fine:

Dim i As Integer = Nothing

VB.Net's Nothing is actually a closer match for C#'s default(T) expression.

VB.NET - Nullable DateTime and Ternary Operator

I will admit that I'm not an expert on this, but apparently it stems from two things:

  1. The If ternary operator can return only one type, in this case a date type, not a nullable date type
  2. The VB.Net Nothing value is not actually null but is equivalent to the default value of the specified type, in this case a date, not a nullable date. Hence the date minimum value.

I derived most of the information for this answer from this SO post: Ternary operator VB vs C#: why resolves to integer and not integer?

Hope this helps and that someone like Joel Coehoorn can shed more light on the subject.

if() operator/function bugs dealing with nothing. IF() doesn't return nothing. Why?

The If operator can be thought of as being like a generic function:

If(Of T)(condition As Boolean,
truePart As T,
falsePart As T) As T

That means that the second and third arguments must be the same type (either explicitly or one can be cast as the other) and the return value will be that same type. With that in mind, let's look at some of your examples.

'2nd msgbox. If(D, Nothing, True) returns false instead of nothing
MsgBox(If(D, Nothing, True), vbOK, "'2nd msgbox.")

So, for that to work at all, the second and third as the same type. What type could that possibly be? The type of the second argument is unspecified while the type of the third is Boolean. Nothing can be cast as type Boolean so that's what happens, and the return value is thus also Boolean. Casting Nothing as type Boolean yields False, so the second argument is effectively False and that's what gets returned.

Dim UnevaluatedPart As Nullable(Of Integer)

' 8th. Now it returns nothing with integer? as third argument (false part)
MsgBox(If(True, Nothing, UnevaluatedPart), vbOK, "8th. Now it returns nothing")

' 9th. Proof of above (it's really nothing not empty string ""
MsgBox(If(True, Nothing, UnevaluatedPart) Is Nothing, vbOK, "' 9th. Proof of above")

In both these cases, the type of the second parameter is unspecified and the type of the third parameter is Integer? so Nothing gets cast as type Integer?. That means that both the second and third arguments are a Integer? with no value. You're going to get the same return value whether the condition is True or False. Of course it won't be an empty String because the return value MUST be type Integer?. It's not just Nothing though; it's a Integer? with no value, so you can actually test the HasValue property of that result.

' 5th. this returns different result (int format) but again not the expected nothing
MsgBox(If(True, Nothing, 15), vbOK, "5th.")

Again, the type of the second argument is unspecified so the argument and return type is inferred from the third argument. That third argument is type Integer so that means that Nothing is cast as type Integer, which yields zero. The condition is True so it is that zero value that gets returned. If you tested whether that was equal to Nothing then you'd find that it is, which is exactly why that's what Nothing got converted to for the second parameter.

Is there a VB.NET expression that *always* yields null?

The first answer I gave missed some points, but this should do it:

Dim o As Object = If(myBool, 5, DirectCast(Nullable.GetUnderlyingType(GetType(Integer)), Object))

This uses the fact that Nullable.GetUnderlyingType will return a null reference if you pass it a type which isn't a nullable value type - which Integer isn't. Other alternatives exist, such as Type.GetElementType(), or perhaps GetType(Object).BaseType.

I've checked that this works with multiple different types for the second operand.

It's slightly annoying that you have to cast to Object... I'm still working on alternatives for that...

Nullable type inference in Visual Basic – is it documented somewhere and can it be made more strict?

Okay, now I understand better. The culprit is in interpretation of Nothing.

Change of Nothing to “true” null leads to correct result:

Dim i As Integer? = If(True, New Nullable(Of Integer), 3)

Result: i Is Nothing

so the possible problem was that Nothing seems to be first viewed by compiler as default value for the other type (Integer) than a null. Changing its implicit meaning helps. A tricky spot anyway. If someone can find this documented, it would be nice. (I do not insist on this answer.) It will be great if the VB can be forced to throw an error or warning when this happens, similar to C#.


As seen in comment elsewhere, a nicer form of notation can exist:

Dim i As Integer? = If(True, Integer?, 3)

Nice!

Is Nothing equal to Default?

If it's a value type (like Integer, Double, etc.) setting the variable to Nothing will set it to the default value.

If it's a reference type, it will really be set to Nothing (null value).

In Microsoft's words:

Assigning Nothing to a variable sets
it to the default value for its
declared type.

If the variable is of a reference
type, a value of Nothing means that
the variable is not associated with
any object. The variable has a null
value.

Bug?? If you assign a value to a nullable integer via a ternary operator, it can't become null

The problem is that Nothing in VB.NET works differently than, for example, null in C#. When Nothing is used in the context of a value type (such as Integer) it represents the default value of that type. In this case, that's 0.

In your first example, both branches of the ternary operator are valid Integer values. The true branch represents 0 and the false branch represents 43.

In the second example, neither branch of the ternary operator is a valid Integer value, thus forcing the VB.NET compiler to assume that the overall operator returns Object, not Integer.

To make the first example work the way you intend, you need to make it clear to the compiler that the ternary operator should resolve to an Integer?, not an Integer or an Object. You can do so like this:

dim val1 As Integer? = If(5 > 2, Nothing, New Integer?(43))

By explicitly making the false branch of the operator an Integer?, the Nothing in the true branch will represent the null value, instead of the default Integer value.

Benefits of using the conditional ?: (ternary) operator

I would basically recommend using it only when the resulting statement is extremely short and represents a significant increase in conciseness over the if/else equivalent without sacrificing readability.

Good example:

int result = Check() ? 1 : 0;

Bad example:

int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;

Conditional operator assignment with Nullablevalue types?

The problem occurs because the conditional operator doesn't look at how the value is used (assigned in this case) to determine the type of the expression -- just the true/false values. In this case, you have a null and an Int32, and the type can not be determined (there are real reasons it can't just assume Nullable<Int32>).

If you really want to use it in this way, you must cast one of the values to Nullable<Int32> yourself, so C# can resolve the type:

EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? (int?)null
: Convert.ToInt32(employeeNumberTextBox.Text),

or

EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? null
: (int?)Convert.ToInt32(employeeNumberTextBox.Text),


Related Topics



Leave a reply



Submit