Req24: warnings where "Nothing" isn’t null


[This post is part of a series, “wish-list for future versions of VB“]


 


IDEA: Emit a warning where “Nothing” is used in a likely-incorrect way. 99% of users think that “Nothing” means the same as C#’s “null”, i.e. a null reference or empty nullable — but it isn’t. Nothing is instead the same as C#’s “default(T)”. Also, 99% of users don’t realise that VB does null-propagation for all operators including the equality operator. We should give warnings in cases where we’re overwhelmingly sure that Nothing is being misused.


 


Example 1.


Dim x As Integer? = If(False, 1, Nothing)


‘ gives x.HasValue=True, x.Value=0


It’s hard, though, to know exactly what conditions would trigger the warning. One example condition, which would catch the above case, is “Warn when Nothing means the same thing as the number 0, since the user should have just written 0 instead”.


 


Example 2.


Dim x As Boolean? = Nothing


If x = Nothing Then Console.WriteLine(“is nothing”)


‘ doesn’t print anything


Contrary to common expectations, this code doesn’t print anything. The condition we could use to catch this is, “Warn when the user writes an equality operator expr = Nothing or Nothing = expr in the case where expr has nullable type.” And indeed in VS2010 we already did introduce this warning!


 


Example 3.


Private _AccessLevel As Integer?


Public Property AccessLevel As Integer?


    Get


        Return _AccessLevel


    End Get


    Set(ByVal v As Integer?)


        If _AccessLevel Is Nothing OrElse _AccessLevel <> v Then _AccessLevel = v


    End Set


End Property


 


AccessLevel = 15


AccessLevel = Nothing


Console.WriteLine(AccessLevel)


‘ prints 15: the second assignment didn’t do what we expected


In this case the user has written the wrong conditions inside the property setter. The condition we could use to catch this? I don’t know. It’s not clear. But note that in this case the expression “_AccessLevel <> v” has type Boolean?. Bill McCarthy suggested that we emit a warning whenever a comparison operator (<, >, <>, =) produces a Boolean? but is used in a conditional statement that expects just a Boolean. It’s a clever idea but I worry it will have too many false positives.


 


 


Other ideas. One possibility is to add two new keywords to VB, “null” and “default(T)” like in C#. Then we could deprecate “Nothing”. This would be a bit of a shame in some cases, though, e.g.


    Sub f(Optional ByVal x As IntPtr = Nothing)


    void f(IntPtr x = default(IntPtr))


But in general, we think that throwing in extra keywords which do almost the same as existing keywords is a bad idea (witness the current confusion over CType vs DirectCast vs TryCast vs CTypeDynamic). We would also not want to deprecate a code construct that’s used in 99% of user projects out there.


 


 


Provisional evaluation from VB team: Adding extra warnings is a good idea. We’re not sure we’ve figured out exactly the right conditions that would trigger the warnings, though. We worry that the conditions above will produce false positives, i.e. they will warn in perfectly legitimate code. We also worry that they will produce false negatives, i.e. they will fail to detect cases that should be caught.


If you have been burnt by “Nothing” not being null, please post with your code snippets. That will help us evaluate whether our conditions are appropriate. Thanks!


 


 

Comments (7)

  1. MarkJ says:

    Pressed Submit a bit early there, sorry!

    The extra warnings are a very good idea. The extra keywords are not a good idea. Try to avoid false positives if you can. False negatives are best avoided but are not a reason to leave out a particular warning – every little helps.

  2. Dzonny says:

    * Please, do not deprecate Nothing – it’s Visual Basic!

    * Warning when Nothing is probably misused are good idea – but, please, create several categories of Nothing-related warnings and allow us to turn them on and off at project level and via some #Pragma NoWarn as well.

    * New keywords Null and Default – I’m not strongly against it, but I’m just happy without them.

  3. Héctor says:

    I’d appreciate if Nothing would be separated to Null and Default(Of T). It hurts my eyes when I see some of my partners do things like:

    Dim i As Integer = 10

    i = Nothing

    Also, I’d love to see if "=" could be used to compare against Null or other objects. It looks better to make:

    If buttonA = buttonB Then

    Rather than:

    If buttonA.Equals(buttonB) Then

  4. Kyralessa says:

    I think having the warnings isn’t a bad idea at all.  Anything that’s relatively unobtrusive and helps people write better code can’t be a bad thing.

  5. My biggest problem with Nothing is that it is context sensitive. If you have a variable typed as Object, assigning Nothing to it results in a Null when you may have preferred the default value of a boolean or Integer. Especially with generics support, it would be nice to have something like Nothing(T). For example:

    Sub ResetColumnValue(Of T)(row as DataRow, columnIndex as Integer)

       row(columnIndex) = Nothing(T)

    End Sub

  6. Anthony D. Green says:

    Cyborgx372, to get Nothing(T) as in your generic example, you can use CType.

       row(columnIndex) = CType(Nothing, T)

    You're correct that Nothing is context sensitive, but you can always insert your own context:

       Static defaultValue As T = Nothing

       row(columnIndex) = defaultValue

    would also work.

    -ADG

  7. Anthony D. Green says:

    Héctor,

    The correct way to compare against null or other objects in Visual Basic is to use the Is and IsNot operators. They only work with reference equality (the equivalent of Object.ReferenceEquals) so even if the class overloads the = and <> operators they'll still compare instances.

    If buttonA Is buttonB Then …

    If buttonA Is Nothing Then …

    If buttonA IsNot Nothing AndAlso buttonA IsNot buttonB Then …

    -ADG