7

Given the following code:

Dim widthStr As String = Nothing

This works - width is assigned Nothing:

Dim width As Nullable(Of Double)
If widthStr Is Nothing Then
  width = Nothing
Else
  width = CDbl(widthStr)
End If

But this does not - width becomes 0.0 (although it seems to be logically identical code):

Dim width As Nullable(Of Double) = If(widthStr Is Nothing, Nothing, CDbl(widthStr))

Why? Is there anything I can do to make it work?

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
  • did you try the same in C#? `double? width = widthStr != null ? Double.Parse(widthStr) : (double?)null;` – Federico Berasategui Jan 31 '13 at 19:43
  • please check http://stackoverflow.com/questions/14633824/nullable-type-with-inline-if-cannot-work-together http://stackoverflow.com/questions/2647558/preserving-null-values-in-a-double-variable – spajce Jan 31 '13 at 19:44
  • 2
    @HighCore - `null` in C# and `Nothing` in VB.Net are *not* equivalent. `Nothing` is, approximately, `default(T)`. – Damien_The_Unbeliever Jan 31 '13 at 19:49

2 Answers2

12

Further to Damien's answer, the clean way to do this is to not use Nothing, but New Double? instead:

Dim width As Double? = If(widthStr Is Nothing, New Double?, CDbl(widthStr))

And now that the type of the If expression is correct, this could be reduced to:

Dim width = If(widthStr Is Nothing, New Double?, CDbl(widthStr))
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
  • +1. Thanks for a suggestion. I generally prefer not to use any of the special characters, for code clarity. So `Dim width As Nullable(Of Double) = If(widthStr Is Nothing, New Nullable(Of Double), CDbl(widthStr))` is more preferable. – Victor Zakharov Feb 02 '13 at 17:28
  • I understand your preference to not use "special characters" (I wouldn't use any type characters for variables -- but I will for constants.) but in this case the IDE throws errors referring to the `?` form for `Nullable(Of )`. – Mark Hurd Feb 03 '13 at 02:34
  • No, just that when dealing with errors regarding code that uses `Nullable(Of Something)` the VB.NET compiler refers to `Something?`. – Mark Hurd Feb 03 '13 at 13:05
5

This all comes down to type analysis of expressions.

Nothing is a magical beast in VB.Net. It's approximately the same as default(T) in C#.

As such, when trying to determine the best type for the following:

If(widthStr Is Nothing, Nothing, CDbl(widthStr))

The third argument is of type Double. The second argument is convertible to Double (because Nothing can return the default value of value types). As such, the type of the return value of If is determined to be Double.

Only after that piece of type analysis has concluded is any attention paid to the type of the variable to which this expression is being assigned. And Double is assignable to Double? without any warnings.


There's no clean way to make your If() expression work how you expected. Because there's no equivalent to null in VB.Net. You'd need (at the least) to insert a DirectCast (or equivalent) on one side or another of the potential results of the If to force the type analysis to see Double? rather than Double.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • +1, even though I don't think I completely understand your answer. Are you suggesting that such inline `If` is a generic function under the hood? And that's how VS works for inferring types for it? – Victor Zakharov Jan 31 '13 at 19:54
  • @Neolisk - I've edited my question a few times since first posted - have you read the most recent version? `If` isn't a generic function. But `Nothing` is, as I've said, a magical beast. It's typeless (in and of itself) and so any other type information is used first. – Damien_The_Unbeliever Jan 31 '13 at 19:58
  • Interesting, although I would expect type analysis to consider the type of the left side of equation. Anyway, thanks for such a thorough explanation. – Victor Zakharov Jan 31 '13 at 20:04
  • @Neolisk - frequently, there *is* no left side (consider a `Dim` without a type, any subexpression, or use as a parameter to a function - it has to determine the type of the result of the expression before it can determine which overload to call) – Damien_The_Unbeliever Jan 31 '13 at 20:09