theB3RV
theB3RV

Reputation: 924

VB Single line with null values

I have the following code that I don't believe is functioning properly and I cannot figure out why.

dim total as decimal? = If(first Is Nothing OrElse second Is Nothing, _
                           Nothing, _
                           Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D)))

If either first or second are nothing, then nothing needs to be placed in the total. However, if they both have values, they both need to be changed to positive values and first - second needs to be calculated. First and second are both nullable decimals (decimal?).

Expected results:

first = nothing
second = nothing
total = nothing

Actual results:

first = nothing
second = nothing
total = 0D

I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total

Upvotes: 0

Views: 215

Answers (2)

theB3RV
theB3RV

Reputation: 924

I have reverted to make a compiler extension that allows the absolute value function to be performed on a nullable decimal, returning the value if it is Nothing or non-negative, otherwise multiply by -1 and return. That way if it returns nothing the computation result is as expected.

dim total as decimal? = first.ToAbsoluteValue() - second.ToAbsoluteValue()

<System.Runtime.CompilerServices.Extension()> Friend Function ToAbsoluteValue(value As Decimal?) As Decimal? If value Is Nothing OrElse value >= 0 Then Return value Return Math.Abs(If(value, 0D)) End Function

If anyone knows how to add this to the Math.Abs() overloads that would be a much cleaner option.

Upvotes: 0

Joel Coehoorn
Joel Coehoorn

Reputation: 415705

The If() operator is strongly-typed, but the compiler has to infer the type of the result based on the inputs.

In this case, it can't infer the type from the first option (Nothing), because Nothing by itself has no type, and unlike C#'s null, Nothing can reduce to a value type (this will be important in a moment). Therefore the compiler has to look at the second option: Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D)). The type of this expression evaluates out to a Decimal... not a Decimal?. Therefore, the resulting type of your entire If() expression is a Decimal, and not a Decimal?. That you assign the result to a Decimal? doesn't matter.

I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total

That is exactly what it's doing. However, as mentioned earlier, Nothing in VB.Net can be assigned to value types. Before the assignment can occur, Nothing is converted to a Decimal, because this is the result type of that If() expression. In case of a Decimal, assigning the value of Nothing results in the default Decimal value of 0D... hence your results.

I haven't tested this, but I think you could fix this to get your desired results by explicitly casting the False expression in your If() operator as a Decimal?/Nullable(Of Decimal). This will tell the compiler to infer Decimal? instead of Decimal for the type of the If() expression, and therefore returning Nothing from that expression will have desired output.

Upvotes: 2

Related Questions