Ternary operator VB vs C#: why resolves Nothing to zero?

13,423

Solution 1

This is because VB's Nothing is not a direct equivalent to C#'s null.

For example, in C# this code will not compile:

int i = null;

But this VB.Net code works just fine:

Dim i As Integer = Nothing

VB.Net's Nothing is actually a closer match for C#'s default(T) expression.

Solution 2

The ternary operator can only return one type.

In C#, it tries to choose a type based on null and 42. Well, null doesn't have a type, so it decides that the return type of the ternary operator is that of 42; a plain old int. Then it complains because you can't return null as a plain old int. When you coerce 42 as a int?, the ternary operator is going to return an int?, so null's valid.

Now, I don't know about VB, but quoting from the MSDN,
Assigning Nothing to a variable sets it to the default value for its declared type.

Which, since VB determines that the ternary operator will return an int (using the same process C# did), Nothing is 0. Again, coercing the 42 to be an int? turns Nothing into the default value of int?, which is null, as you expected.

Solution 3

Nothing and null are not the same thing... from the MSDN:

Assigning Nothing to a variable sets it to the default value for its declared type.

Also

If you supply a value type in Expression, IsNothing always returns False.

Keep in mind that int? is a nullable type, but it's still a value type, not a reference type.

Try setting it to DbNull.Value instead of Nothing...

Solution 4

I am thinking this has something more to do with IF than with Nothing. Consider this code:

''#     This raises an exception
Dim x As Integer?
x = If(True, Nothing, Nothing)
MessageBox.Show(x.Value)

''#     As does 
Dim x As Integer?
x = Nothing
MessageBox.Show(x.Value)

''#     Changing one of the truthpart arguments of If is what seems to return the zero.
Dim x As Integer?
x = If(True, Nothing, 5)
MessageBox.Show(x.Value)

Why it is doing this I still don't know, probably a question for the VB team. I don't think it has to do with the Nothing keyword or Nullable.

Solution 5

In a number of cases Nothing will get converted to the default value. To use Nothing the same way you would use null you need to cast it to the correct nullable type.

Dim str As String
Dim int As Nullable(Of Integer) ' or use As Integer?
Dim reader As SqlDataReader
Dim colA As Integer = reader.GetOrdinal("colA")
Dim colB As Integer = reader.GetOrdinal("colB")
str = If(reader.IsDBNull(colA), DirectCast(Nothing, String), reader.GetString(colA))
int = If(reader.IsDBNull(colB), DirectCast(Nothing, Nullable(Of Integer)), reader.GetInt32(colB))
Share:
13,423

Related videos on Youtube

aelveborn
Author by

aelveborn

#SOreadytohelp

Updated on December 07, 2020

Comments

  • aelveborn
    aelveborn over 3 years

    I just shoot myself in the foot and would like to know whether there were actual reasons to make this situation possible.
    And anyway, this question can stay for the convenience of the future foot shooters.


    Suppose we have a nullable value in vb.net:

    Dim i as Integer?
    

    We want to assign a value to it, basing on a condition, and using a ternary operator, because it's so neat and stuff:

    i = If(condition(), Nothing, 42)
    

    That is, if a condition is true, employ the nullability, otherwise the value.
    At which point the shooting occurs. For no apparent reason VB compiler decides that the common base type for Nothing and Integer is Integer, at which point it silently translates the statement to:

    i = If(condition(), 0, 42)
    

    Now, if you were to do this in C#:

    i = (condition()) ? null : 42;
    

    You would immediately get a compiler error saying that <null> doesn't mix well with int. Which is great, as my foot would have been healthier had I went the C# way this time. And for this to compile, you have to explicitly write:

    i = (condition()) ? null : (int?)42;
    

    Now, you can do the same in VB and get the correct null-ness you would expect:

    i = If(condition(), Nothing, CType(42, Integer?))
    

    But that requires having your foot shot in the first place. There's no compiler error and there's no warning. That's with Explicit On and Strict On.


    So my question is, why?
    Should I take this as a compiler bug?
    Or can someone explain why the compiler behaves this way?

    • cdhowie
      cdhowie over 13 years
      Because, as you are finding out, VB is a horrid language that does random stuff you didn't ask it to in a misguided effort to be helpful.
    • codymanix
      codymanix over 13 years
      You would have to cast Nothing to Integer?.
    • Joel Coehoorn
      Joel Coehoorn over 13 years
      @cdhowie - Don't knock it unless you've tried for more than a couple weeks. VB.Net has come a long way from vb6.
    • cdhowie
      cdhowie over 13 years
      @Joel: I will agree with that, but a polished turd is still a turd. :)
    • James King
      James King over 13 years
      Yes, and the differences between VB and C# have become few and rare over the years. This one isn't really a difference... the 'difference' is that Nothing and null have different meanings... it's easy to think you're doing the same thing, but you're not.
    • MarkJ
      MarkJ over 13 years
      @cdhowie Anyone who hasn't learnt the special features of a new language will find that language frustrating. Anyone who blames the language for that frustration needs to reconsider their reaction.
    • Alex Essilfie
      Alex Essilfie over 13 years
      @cdhowie You're obviously one of the people suffering from the my language is better than yours syndrome. Better get over it. VB is worth its salt. How many times [if ever] have you seen C# used as a macro/scripting language? And that's just for starters. I use both languages equally well and I don't complain.
    • cdhowie
      cdhowie over 13 years
      @Alex Nah, I'm one of those people who has used a lot of different languages. I started programming with C64 BASIC and from there moved to VB1 and eventually VB4, 5, 6, and .NET. It's not like I haven't been around the VB block, and that makes it my language as much as anyone else's. I've put up with its crap long enough to know why I don't like it.
    • Jonathan Allen
      Jonathan Allen over 13 years
      When working with nullable ints, I prefer to say new Integer? instead of nothing. It is more verbose, but it elminates confusion.
    • Mark Hurd
      Mark Hurd over 10 years
      @JonathanAllen And it's not more verbose than the 'correct' i = If(condition(), Nothing, CType(42, Integer?)):i.e. i = If(condition(), New Integer?, 42)
  • Joel Coehoorn
    Joel Coehoorn over 13 years
    Yes, it was a typo. Fixed it now.
  • Jon B
    Jon B over 13 years
    Phew, for a few seconds there I thought I was going to have to fix a lot of code!
  • Jon B
    Jon B over 13 years
    this explains why int i = null; doesn't work, but if int? i = 0; and int? i = null both work, why doesn't int? i = condition()? null : 0; ???
  • Joel Coehoorn
    Joel Coehoorn over 13 years
    @Jon I can't answer that, but he's asking about vb code. A translation of the vb to c# would be more like int? i = condition()?default(int):0;
  • aelveborn
    aelveborn over 13 years
    Right. I completely overlooked the fact that you can default() a value type by setting to Nothing. Thanks, got it now.
  • jmoreno
    jmoreno about 9 years
    This has everything to do with Nothing being a Keyword and not a value. As the accepted answer points out, nothing really means Default(T). So, in your first example T evaluates to Integer? and in your second it evaluates to Integer. Which matches your results.
  • aelveborn
    aelveborn over 6 years
    The fact that testInt is of type Integer? already makes the entire expression Integer?, without a need for New Integer?. This was possible long before VS2015, and it is not what the question was about.
  • Joel Coehoorn
    Joel Coehoorn almost 5 years
    @JonB Actually, I can answer this now. The condition()?null:0 expression has to stand on it's own; the target of the assignment doesn't matter. When the compiler goes to infer a type for the expression, the untyped null and 0 operands are not obviously compatible, because int? is still a value type and there's other "magic" going on to allow you assign null to it. It would be nice if the compiler were smart enough to choose int? in that situation, but it won't do that yet.