10

Coming from Basic boolean logic in C#, I was wondering why:

Dim b As Boolean
Dim obj As Object = Nothing
'followig evaluates to False'
b = DirectCast(Nothing, Boolean)
'This throws an "Object reference not set to an instance of an object"-Exception'
b = DirectCast(obj, Boolean)

A CType(obj, Boolean) would evaluate to False(just as CBool(obj)). I think it is because the compiler uses a helper function, but that is not my theme.

Why does casting Nothing to Boolean evaluates to False, whereas casting an object that is Nothing to Boolean throws an Nullreference-Exception? Does that make sense?

[Option Strict ON]
Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • some answer in here refer to framework 2.0, this is about 3.5. there is nullable type in 3.5 for VB – Fredou Jan 26 '11 at 13:51
  • @Fredou: The answer to this question isn't dependent on a particular version of the Framework, and nullable types are not the solution. The asker isn't looking for a *solution*, but rather than *explanation* why the code behaves as it does. – Cody Gray - on strike Jan 26 '11 at 14:21

5 Answers5

16

Presumably, this is because Nothing in VB.NET is not exactly the same thing as null in C#.

In the case of value types, Nothing implies the default value of that type. In the case of a Boolean, the default value is False, so the cast succeeds.

One of the primary differences between value types such as Integer or structures and reference types such as Form or String is that reference types support a null value. That is to say, a reference type variable can contain the value Nothing, which means that the variable doesn't actually refer to a value. In contrast, a value type variable always contains a value. An Integer variable always contains a number, even if that number is zero. If you assign the value Nothing to a value type variable, the value type variable just gets assigned its default value (in the case of Integer, that default value is zero). There is no way in the current CLR to look at an Integer variable and determine whether it has never been assigned a value - the fact that it contains zero doesn't necessarily mean that it hasn't been assigned a value.
    –The Truth about Nullable Types and VB...

EDIT: For further clarification, the reason the second example throws a NullReferenceException at run-time is because the CLR is attempting to unbox the Object (a reference type) to a Boolean. This fails, of course, because the object was initialized with a null reference (setting it equal to Nothing):

Dim obj As Object = Nothing

Remember that, as I explained above, the VB.NET keyword Nothing still works the same way as null in C# when it comes to reference types. That explains why you're getting a NullReferenceException because the object you're attempting to cast is literally a null reference. It does not contain a value at all, and therefore cannot be unboxed to a Boolean type.

You don't see the same behavior when you try to cast the keyword Nothing to a Boolean, i.e.:

Dim b As Boolean = DirectCast(Nothing, Boolean)

because the keyword Nothing (this time, in the case of value types) simply means "the default value of this type". In the case of a Boolean, that's False, so the cast is logical and straightforward.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Thank you. But it is still not pointed out why an Nullreference-Exception will be thrown on runtime, if i try to cast an object that is nothing to a boolean. It could also be casted to false because the default value for boolean is false. – Tim Schmelter Jan 26 '11 at 12:29
  • @Tim: No, it couldn't. At least, not necessarily. Remember that an `Object` is a *reference type*, not a value type. As I explained, the `Nothing` keyword still works the same way as `null` in C# when it comes to reference types. When you set a variable of type `Object` to `Nothing`, that means it does not contain a value. – Cody Gray - on strike Jan 26 '11 at 12:35
  • @Cody gray: That means the CLR is looking whether the object is a value type or a reference type. If the latter it directly throws a NullReferenceException if it should do something with it(f.e. casting). If i try to cast `Nothing` to a Boolean the compiler implicitly assignes `False` to it, hence the CLR will not throw an exception because the casting is not done on runtime but on compile-time. Correct? – Tim Schmelter Jan 26 '11 at 12:51
  • this quote (The Truth about Nullable Types and VB) is for framework 2.0, this question is about 3.5, so use nullable variable aka Dim b as boolean? or dim b as nullable(of boolean) – Fredou Jan 26 '11 at 13:44
  • @Fredou: i didn't want to know if it's possible to cast a null-reference object to a boolean without a Nullreference-Exception, but to know what's going on behind the scenes(compiler,CLR). – Tim Schmelter Jan 26 '11 at 14:04
  • @Tim: Yes, the CLR is attempting to *unbox* the `Object` (a reference type) to a `Boolean`. This fails, of course, because you've assigned a null reference (which is what `Nothing` means for reference types). That's why you're getting a `NullReferenceException`, because the object is literally a null reference. You don't see the same behavior when you try to cast the keyword `Nothing` to a `Boolean` because the keyword `Nothing` (in the case of reference types) simply means "the default value of this type". In the case of a `Boolean`, that's `False`. Does that answer your question? – Cody Gray - on strike Jan 26 '11 at 14:25
  • @Cody Gray: Yes it does. If you would add this comment to your answer i would accept it. Thanks. – Tim Schmelter Jan 26 '11 at 14:35
  • @Tim: Excellent. I've updated my answer, although I think the comments make a little bit more sense when read in context. @downvoter: What part of my answer do you disagree with? If you think there's a correction that I need to make, I'd be happy to do so. – Cody Gray - on strike Jan 26 '11 at 15:06
4

There's a couple of things you have to realize here.

The first is what others have already pointed out: Nothing can be interpreted by the VB compiler as simply the Boolean value False given the proper context, such as Dim b As Boolean = Nothing.

This means that when the compiler sees this:

b = DirectCast(Nothing, Boolean)

It sees a literal (Nothing) and also sees that you want to use this literal as a Boolean. That makes it a no-brainer.

But now here's the second thing you have to realize. DirectCast on an Object is essentially an unboxing operation (for value types). So what needs to happen from the VB compiler's perspective is: there needs to be a Boolean in that box, or else the operation will fail. Since there is in fact nothing in the box—and this time we're really talking nothing, as in null—it throws an exception.

If I were to translate this code to C#, it would look like this:

bool b;
object obj = null;

b = (bool)default(bool);

b = (bool)obj;

Hopefully that makes things a bit clearer?

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • +1 Although a minor quibble. I'm not sure about the wording of "we're really talking `Nothing`" when (I think) you mean a reference variable containing `Nothing` rather than the literal `Nothing`. Surely the literal `Nothing` is as real as it gets? Anyway, this is a better answer than mine was... – MarkJ Jan 26 '11 at 15:02
2

There's a difference between using the keyword (literal) Nothing, and using a reference variable whose value is Nothing.

  • In VB.NET, the literal (keyword) Nothing gets special treatment. The Nothing keyword can be automatically converted into a value type, using the default value of that type.

  • A reference variable whose value is Nothing is different. You don't get the special behaviour.

  • The documentation says DirectCast "requires an inheritance or implementation relationship between the data types of the two arguments".

  • Clearly Object does not inherit from or implement Boolean, unless you have put a boxed Boolean into an object variable.

So the code below fails at runtime with an exception.

 Dim obj As Object = Nothing  
 b = DirectCast(obj, Boolean) 
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MarkJ
  • 30,070
  • 5
  • 68
  • 111
  • As i have mentioned at the end of my question, i have `Option Strict` but it fails on runtime. Have a look at my last comment on Cody Gray's answer. Thanks anyway. – Tim Schmelter Jan 26 '11 at 13:22
  • 3
    This answer it totally right except for that last part, which, as Tim notes, is not related to the problem. (`Option Strict` is not going to prevent you from downcasting an `Object` to a `Boolean`; that always *could* work assuming it's a boxed `Boolean`!) – Dan Tao Jan 26 '11 at 13:51
  • @Tim @Dan Oops, thanks, I will delete that last bit. Oh and +1 to Dan's answer too. – MarkJ Jan 26 '11 at 14:57
  • @Tim Also, +1 to the question. Made me think anyway! – MarkJ Jan 26 '11 at 15:04
  • It may sometimes be helpful to think it terms of there being "parallel universes" of storage location types and heap-object types; defining a value type will actually a separate type in each universe (the official CIL documentation doesn't use the term "parallel universe", but does refer to the existence of separate types). The two types mostly behave similarly, but not identically; special rules come into play when crossing between the two universes. Casting `Object` to `Boolean` requires going between universes, while casting `Nothing` to `Boolean` does not. – supercat Dec 03 '13 at 19:22
1

I'm finding that comparing of the Boolean variable to a string of "True", "False" or Is nothing seems to ensure that I get the correct comparisons. I was using a function to return an html string of a div with an image of a checked or unchecked radio button and was having the issue of nothing coming back as false. Using the variable = "True" or "False" string and doing the last check with IS NOTHING helped to resolve that issue.

Dim b as boolean = nothing

response.write CheckValue(b = "True")
response.write (b = "False")
response.write (b is nothing)

Function CheckValue(inVal as boolean) as string
  if inVal then 
    return ("<div><img src="checked.png" ></div>
  else
    return ("<div><img src="unchecked.png" ></div>    
  end if
end function

The system seems to do the conversion to string when implicitly compared to a string whereas using the .tostring method just creates an error while allowing the last comparison to actually compare to a value of nothing.

Hopefully that helps somewhat. It at least let me

Harry B.
  • 11
  • 2
  • `isNothing(b)` in a condition statement will indeed work as a by-pass to the `Nothing`. The answer above is correct but I'm glad someone found a way around it, hence the upvote. – NewBie1234 Oct 10 '18 at 01:17
1

To get the expected behavior, you need this code:

Dim b As Boolean?
Dim obj As Object = Nothing  
b = DirectCast(obj, Boolean?) 

The character ? mean Nullable(of ).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fredou
  • 19,848
  • 10
  • 58
  • 113
  • It would be the expected behaviour if i would get an InvalidCast-Exception on compiletime. It was also more an theoretical question why the vb.net compiler behaves different to the C#. Thanks for the hint, i will change to VS 2010 next week, then i'm able to use this syntax. – Tim Schmelter Jan 26 '11 at 13:52