views:

161

answers:

6

In VB.net, what is the difference between

if foo is Nothing Then
doStuff()
End If

and

if foo=Nothing Then
doStuff()
End If

Update I received the following answer:

foo is Nothing simply checks if foo is not assigned to any reference.
foo=Nothing checks if the reference held by foo is equal to nothing

After running the following three statements:

Dim foo as Object
Dim bar as Integer
foo = bar

foo is Nothing evaluates to false and foo = Nothing evaluates to true.

However, if bar is declared as an Object and not initialized, then foo is Nothing and foo = Nothing both evaluate to true! I think this is because Integer is a value type and Object is a reference type.

+2  A: 
foo is Nothing simply checks if `foo` is not assigned to any reference.

foo=Nothing checks if the reference held by `foo` is equal to `nothing`

In VB, both statements will evaluate to the same value if foo has not been initialised

J Angwenyi
What if foo is not a reference type? Or what if foo is a string? Are you sure it will evaluate to the same value?
Lasse V. Karlsen
Value types comes into play when the method is generic, but for a blank string (ie. ""), then Is and = will produce different results.
Lasse V. Karlsen
@Lasse, See my answer for when foo is a Nullable(Of T).
Jonathan Allen
A: 

Hi there.

Here's some IL to validate the differences:

.method public static void Main() cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 3
    .locals init (
        [0] object o,
        [1] bool VB$CG$t_bool$S0)
    L_0000: nop 
    L_0001: newobj instance void [mscorlib]System.Object::.ctor()
    L_0006: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
    L_000b: stloc.0 
    L_000c: ldloc.0 
    L_000d: ldnull 
    L_000e: ceq 
    L_0010: stloc.1 
    L_0011: ldloc.1 
    L_0012: brfalse.s L_001f
    L_0014: ldstr "Is Nothing"
    L_0019: call void [mscorlib]System.Console::WriteLine(string)
    L_001e: nop 
    L_001f: nop 
    L_0020: ldloc.0 
    L_0021: ldnull 
    L_0022: ldc.i4.0 
    L_0023: call bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::ConditionalCompareObjectEqual(object, object, bool)
    L_0028: stloc.1 
    L_0029: ldloc.1 
    L_002a: brfalse.s L_0037
    L_002c: ldstr "Is nothing"
    L_0031: call void [mscorlib]System.Console::WriteLine(string)
    L_0036: nop 
    L_0037: nop 
    L_0038: nop 
    L_0039: ret 
}

VB Code:

Sub Main()
        Dim o As New Object

        If o Is Nothing Then
            Console.WriteLine("Is Nothing")
        End If

        If o = Nothing Then
            Console.WriteLine("Is nothing")
        End If
    End Sub

Cheers. Jas.

Jason Evans
Also try this with a string containing Nothing, a string containing "", and a value type, say an integer, and use both the default value for the value type, and something else, ie. leave it at 0, and then check for 1 as well.
Lasse V. Karlsen
@Lasse - Haven't go time to add any more examples I'm afraid. Maybe someone else can do this for reference?
Jason Evans
+1  A: 

foo is a pointer to a memory location and Nothing means 'not pointing to any memory because no memory has been allocated yet'. Equals means that when you are comparing 2 value types they have the same value. But you're assuming foo represents an object, which is always a reference type that is meant to point to an object in memory. 'is' is for comparing object types and will only return 'true' if you have two objects pointing to the same value.

Say you have clsFoo with one public integer member variable 'x' and foo1 and foo2 are both clsFoo, and y and z are integers

foo1=new clsFoo
foo2=new clsFoo
foo1.x=1
foo2.x=1
y=2
z=1
dim b as boolean 

b= foo1 is not foo2  ' b is true
b= foo1.x=foo2.x ' b is tree
b= foo1 is foo2 'b is false  
b= foo1.x=z ' true of course
foo2.x=3
b= foo1.x=foo2.x ' false of course
foo1=foo2
b=foo1 is foo2 ' now it's true
b= foo1.x=foo2.x ' true again
b= 3=3 ' just as this would be
b= foo1=foo2 ' ERROR: Option Strict On disallows operands of type Object for operator '='. Use the 'Is' operator to test for object identity.

NEVER forget to turn option strict on. To fail this is to scream 'PLEASE make my program SUCK.'

FastAl
It seems that you have forgotten Nullable Structures, which should use `Is Nothing` instead of `= Nothing`.
Jonathan Allen
The op's question didn't exactly beg such details, unless he posed it as a contest ;-)
FastAl
+5  A: 

It depends on the type.

  • For value types, Is doesn’t work, only =, and Nothing refers to the default instance of that type (i.e. the instance that you get by calling New T() for a given type T).

  • For reference types, Is performs a reference comparison (identical to object.ReferenceEquals(a, Nothing)). a = Nothing usually does not work, unless Operator = has explicitly been defined for that class.

    If, furthermore, Operator = has been implemented correctly, then foo = Nothing and foo Is Nothing should yield the same result (but the same isn’t true for any other value instead of Nothing) but foo Is Nothing will be more efficient since it’s a compiler intrinsic while Operator = will call a method.

  • For nullable value types (i.e. instances of Nullable(Of T)), special rules apply: like all other operators, = is lifted (notice the error in that blog post …) by the compiler to the underlying type. The result of comparing two Nullables is thus not Boolean but Boolean? (note the ?). However, because of so-called “null propagation” for lifted operators, this will always return Nothing, no matter the value of foo. Quoth the VB10 language specs (§1.86.3):

    If ether (sic!) operand is Nothing, the result of the expression is a value of Nothing typed as the nullable version of the result type.

    So if the users want to compare a Nullable variable to Nothing, they must use the foo Is Nothing syntax for which, once again, the compiler generates special code to make it work (§1.79.3 of the VB10 language specs). Hat tip to Jonathan Allen for (correctly) persisting that I was wrong; hat tip to Jared Parsons for passing me a link to the VB10 specs.

(The above assumes that Option Strict On is used, as you always should. In case that isn’t the case, the results will differ slightly since then calling foo = Nothing may perform a late-bound call.)

Konrad Rudolph
For strings = and Is produce different results, I daresay = is implemented with principle of least surprise for strings so I deem that correct.
Lasse V. Karlsen
@Lasse: Yes, strings are a special case in VB since `=` will call a special method instead of `Equals`, that will treat `Nothing` equal to the empty string.
Konrad Rudolph
You forgot Nullable(Of T). For that `foo = Nothing` will compile, but it gives the wrong answer.
Jonathan Allen
@Jonathan: `Nullable(Of T)` is a value type and my answer still applies. `foo = Nothing` *will* give the correct answer, and it’s equivalent to `Not foo.HasValue`.
Konrad Rudolph
@Konrad. Then tell me why VB 10 gives us the following compiler wanring. `This expression will always evaluate to Nothing (due to null propagation from the equals operator). To check if the value is null consider using 'Is Nothing'.`
Jonathan Allen
@Jonathan: If you can give me the exact code … at the moment, the message doesn’t make much sense.
Konrad Rudolph
Just use these lines `Dim foo As Integer? = Nothing` and `If foo = Nothing Then`
Jonathan Allen
@Jonathan: that’s unrelated. The compiler warns here because the `If` is redundant: *of course* `foo` will always be `Nothing`, since it has been initialized this way and has never been changed. The compiler is smart enough to figure that out but this has got nothing to do with comparability of nullable types. If you don’t believe me, simply try `Dim foo As Integer? = 1`, or `Dim foo As Integer? = If(New Random().NextDouble() < 0.5, 1, CType(Nothing, Integer?))` – which simulates a coin toss so the compiler can’t guess at the value of `foo`.
Konrad Rudolph
If you use `Dim foo As Integer? = 1`, you get the same error message. Heck, if you make foo a parameter you still get the same error message. Try the code in VS 2008 or VS 2010, you won't get the same answer as when you use `foo is Nothing`.
Jonathan Allen
@Jonathan: I concede defeat. The VB language reference is out of date and incomplete, and it doesn’t mention `Nullable` at all (only as an exception to the `Structure` generic constraint). It doesn’t specify its behaviour in comparison but the compiler clearly includes some transformations for `=`, just as for any other operator (and you correctly mentioned null propagation).
Konrad Rudolph
A: 

Asume:

MyFunc(Foo as object)

Foo - Boxed if ValueType

if foo is Nothing Then

object.ReferenceEquals (Code Inlined - Fastest method)

if foo=Nothing Then

Operators.ConditionalCompareObjectEqual(foo, Nothing, False)

Vb.Net carry this case like Obj1 = Obj2. It do´nt uses Obj.equals(obj2) ! Exception if Obj1 is nothing

This option uses a very complex code as there are a lot options depending all posible foo definitions.

try this:

Sub Main()
  Dim o As Object = 0
  Debug.Print(o Is Nothing)  'False
  Debug.Print(o = Nothing)   'True 
End Sub
x77
A: 

It depends on Foo's type.

Reference Types

if foo = Nothing then 'This depends on how the op_Equals operator is defined for Foo. If not defined, then this is a compiler error. 
if foo Is Nothing then 'Evaluates to True is foo is NULL

Value Types

if foo = Nothing then 'Evaluates to True is foo has the default value in every field. For most types the default is 0.
if foo Is Nothing then 'Compiler Error

Nullable Value Types

if foo = Nothing then 'This always evaluates to false. In VB 10, this is a compiler warning
if foo Is Nothing then 'Evaluates to True is foo.HasValue = False

A lot of people don't understand Null Propogation in VB. Like SQL, it uses three-value logic so the answer for "a=b" could be True, False, or Null. In an If statement a Null is treated as a False.

Warning You can't just write If Not(Foo = Nothing) Then because 'Not (Nothing)' is still 'Nothing'.

Jonathan Allen