IIF becomes If, and a true ternary operator

Many months ago, I discussed the fact that we were finally planning to come up with a true ternary conditional operator that would allow short-circuited conditional expressions. (Just as a quick recap: the current problem with the IIF function is that it evaluates all the arguments since it is just a regular method call. So “IIF(x Is Nothing, “Empty”, x.Name)” will throw an exception if x is Nothing, because we still evaluate x.Name.)

At the time, we were considering taking the IIF function and making it intrinsic. In the end, this looked like it would just be too big of a compatibility problem. There were lots and lots of subtleties around the return type and the short-circuiting behavior that were going to pose problems. So instead we simply reused an existing keyword and invented a whole new operator–the If operator. The If operator works just the way you’d expect it–it evaluates the first operand and if it is True, evaluates and returns the second operand. If it it’s False, then it evaluates the third operand and returns that. There is also a binary form of the If operator that takes a reference type or a nullable value type as its first operand. If the value is not Nothing, then the first operand is returned. If the value is Nothing, the second operand is returned. This is useful for doing a database coalesce operation, something like “If(x.Name, “<no name>”)”.

The result type of an If operation depends on the types of the two operands that might be returned from the operation. In general, we pick the wider of the two types. If the two types don’t convert to each other, then you get an error. (For example, if you did “If(<boolean>, <integer>, <long>)”, the result type would be long. If you did “If(<boolean>, <Button>, <string>)”, you’d get an error because there was no conversion between Button and string.)

One question people might have is, “why the parenthesis?” More than a few people have suggested an expression form of the If statement, something like “x = If y Is Nothing Then “<none>” Else y” or other variations that weren’t delimited by parenthesis. In the end, most everything that didn’t use parenthesis as delimiters just ended up looking funny when you put it in an If statement (“If z = If y Is Nothing Then “<none>” Else y Then…”) or funny when you strung a few of them together using AndAlso/OrElse. For what it’s worth…

The If operator won’t appear in Orcas until Beta2, unfortunately. So you’ll still have to wait a bit longer…

(And, as a final piece of trivia, why is the IIF function called “IIF?” It stands for “Immediate If“.)

31 thoughts on “IIF becomes If, and a true ternary operator

  1. Jonathan Allen

    What about DBNull? Will that be treated the same way as Nothing, or will it be returned?

    Dim Name = If (reader("Name"), "Name unknown")

    where reader is a SqlDataReader and reader("Name") is potentially DBNull.Value.

    Reply
  2. ChrisA

    1) Not everything in Wikipedia is true. Remember it’s edited by the masses, and is subject to mythinformation.

    2) In this case, Wikipedia is wrong. It’s been Immediate If for as long as I can rememeber…. that goes back some time.

    Now, I do see that CFML was referenced, so maybe that’s where the "Inline IF" came from, I don’t know. But I think we’re splitting hairs at this point.

    It’s good to see IIF become a true ternary operator, but I would like to ask what was the reasoning on (re)using If rather than a symbolic operand such as (x == y: 1 : 0)?

    Reply
  3. Jonathan Allen

    Personally I always found the (a?b:c) syntax to be rather confusing.

    Consider

    X = a ? b : c ? d : e

    does that translate to

    X = (a ? b : c) ? d : e;

    or

    X = a ? b : (c ? d : e);

    I have no f-ing clue. But when I see this…

    x = if(if(a, b, c), d, e)

    oe this

    x = if(a, b, if (c, d, e))

    then I know exactly what is going on.

    Reply
  4. Geoff Appleby

    I always thought it was ‘If and Only If’, like in mathematics. I stand corrected :)

    Oh, and I like the decision made. Nice.

    Reply
  5. Pingback: DotFrandsen

  6. Kemp

    "X = a ? b : c ? d : e

    does that translate to

    X = (a ? b : c) ? d : e;

    or

    X = a ? b : (c ? d : e);

    I have no f-ing clue. But when I see this…

    x = if(if(a, b, c), d, e)

    oe this

    x = if(a, b, if (c, d, e))

    then I know exactly what is going on. "

    Using parentheses in the second but not the first is unfair, that’s why the first is more confusing.

    Also, this post is an example of why I don’t use VB. In this case giving ‘if’ two meanings : a control structure like every other language uses it as, and a ternary operator.

    Reply
  7. random832

    "if" in programming is _always_ if and only if – if it weren’t, that’d mean the compiler sometimes chooses to execute it anyway even when the condition’s false.

    Reply
  8. random832

    Also, a?b:c?d:e translates essentially to (pseudocode) "if a then b else if c then d else e". not using parens is basically like using

    if(…) {…} else if(…) {…} else {…}

    instead of

    if(…) {…} else { if(…) {…} else {…} }

    they’re equivalent, and the second is what’s really going on, but people like to think of "else if" as analogous to a switch.

    Reply
  9. Anthony D. Green, MCPD

    "Also, this post is an example of why I don’t use VB. In this case giving ‘if’ two meanings : a control structure like every other language uses it as, and a ternary operator. "

    VB isn’t every other language, one of many reasons I DO use it. There can only be so many C-wanna-be languages in common use and extras just die off (*cough J#*).

    How resolving an overloaded keyword confuses you so is beyond me. But at the same time I also don’t mind VB’s overloaded usage of parens or the = operator either so different strokes for different folks.

    Regarding the ? : operator which (has no other name than "the ternary one") … well, I think the lack of a more descriptive name articulates best my issue with it.

    Reply
  10. Pingback: DotFrandsen

  11. Jonathan Allen

    I think the lack of parens in my example is perfectly fair because I have seen it before in code.

    As for overloading the term If, I don’t see the big deal. VB keywords and operators have always been context sensitive. Consider the = operator, which is assignment or comparison depending on the context.

    Also, the question mark is overloaded in C# to be both the ternary operator and to indicate a variable is nullable. At least in VB they are related concepts.

    Finally, if VB used ?: then both the question make and the colon would be overloaded. The first to indicate nullable, the latter to indicate two statements on the same line.

    Reply
  12. Jonathan Allen

    random832, thanks for the reading lesson. I think it will really help when I’m dealing with C code.

    Reply
  13. Someone Who Used to Love VB

    Changing the way If works. Perfect.

    Perfect reason to forget VB ever existed. Genious ideas like this that make the code even less readable.

    VBx, eh? Perfect again. Let’s make sure no one can find any code…. or, I guess, since you’ve never used VB, you don’t know what a VBX file is, right?

    Reply
  14. Anthony D. Green, MCPD

    It’s going to be one of those days, I see.

    At the least, I’d like to know why people so passionately antagonistic of VB monitor new developments in the language trolling for an excuse to come in a spew nonsense on those of us who actually take pleasure in some new developments. You say these are perfect reasons to forget VB ever existed and yet I find myself repeatedly dealing with you. Does "forget" mean something else in C#?

    As for the way If works…, as long as I’ve used it it evaluates some boolean and does one thing if it’s true and optionally another if it isn’t. How this basic concept is utterly departed from in making an operator that evaluates some boolean and returns one thing if it’s true and another if it isn’t is once again beyond me.

    You know, now that I think about it. I understand your problem. The Overloads keyword and what it does, TypeOf … Is operator, And, Or, If – clearly VB is too logical for you. All those years of staring at near unreadable symbolic and arbitrary gibberish in C-derived languages has completely spoiled you from ever appreciating anything that makes sense and as such has rendered any meaningful dialect between us on sensible matters impossible. Perhaps this would be better for you:

    Ad34d >> 349 amd k??? the @# in alius__ nrn; 4th ten.

    Reply
  15. Diego Vega

    Paul,

    I think that changing your plans from short-circuiting IIf() to creating a new role for If() is great. Parenthesis are good too!

    What sounds VERY COUNTERINTUITIVE to me is the semantics of the binary form. I clearly understand the need of a coalesce operator, however, the name would be more consistent with the semantics if it was called IfNot()!

    Other alternatives would be IfNull(), IfNothing(), IsNothing() or IsNull() (SQL Server defines ISNULL() with similar semantics).

    I don’t remember where or when I learned the trick, but I have been defining IfNull() in every language I have worked with for some years.

    In my definition of IfNull() the second parameter is optional. In case the second parameter is not present the method returns the “empty” value (or perhaps I should say “neutral element”) of the type: Cero for numerical types, empty string for string, etc.

    I also usually define NullIf() as the opposite to IfNull(). This one will return null or nothing if both parameters are the same value, or in case the second parameter is not present, if the value of the first parameter is the “neutral element” of the type.

    PS: I was sure the the first I in IIF meant "Inline"! :)

    Reply
  16. Diego Vega

    Oh, and I forgot to mention DBNull. I agree with the first commenter. Even if DBNull can be seen now as "legacy", everything that gives it the same meaning as Null or Nothing is good help.

    Reply
  17. paulvick

    Currently, the plans are NOT to support DBNull for the coalesce version of the operator, but we’ll look at the idea and see if there’s something we can do about it. Thanks!

    Reply
  18. Pingback: Sorting It All Out

  19. Bob Calco

    My suggestion:

    <res1> If <conditional> [Else <res2>]

    Sort of like Ruby’s inverse-if syntax, e.g.,

    return false if @a > 5

    Only the Else part could be optional (so I guess it would be two different syntax elements… an inverse-if expression, or a ternary-operator-expression).

    Example:

    Class Foo

    Public Value As Integer = 1

    End Class

    Dim f as Foo



    Dim i as Integer = f.Value If f IsNot Nothing Else 0

    Another cleaner example:

    Dim isOldEnough As Boolean

    isOldEnough = true If customer.Age > 18 Else False

    If you’re really making it a ternary operator, then the operator should be ‘op1 If op2 Else op3′, similar to C#’s ‘op1 ? op2 : op3′ operator except VB’s conditional is op2 operand instead of op1.

    To me that looks like VB and is human-readable too without resorting to requiring unnecessary parentheses.

    Sincerely,

    Bob Calco

    Reply
  20. Bob Calco

    Another alternative to If..Else that is more readable (and slightly more verbose, as if that’s a sin):

    <res1> If <conditional> Otherwise <res2>

    Dim isOldEnough = True If customer.Age > 18 Otherwise False

    Naturally _ can be used to break the line up for readability:

    Dim isOldEnough = True If customer.Age > 18 _

    Otherwise False

    Just a thought.

    Sincerely,

    Bob Calco

    Reply
  21. Bob Calco

    WRT the DBNull "problem", why wouldn’t this work?:

    Dim name = String.Empty If _reader("Name").IsDBNull Otherwise _reader("Name")

    Sincerely,

    Bob Calco

    Reply
  22. Pingback: Panopticon Central

  23. Pingback: Panopticon Central

  24. Pingback: Samurai Programmer.com

  25. Theodore

    I seem to have found a rather strange bug with this operator…it sometimes returns the wrong value of Nothing.

    For example,
    Dim d As Nullable(Of Date) = If(True, Nothing, Nothing)
    …will set d to a value that displays as #12:00:00 AM# in the debugger, instead of setting it to Nothing.

    If that kind of bug is going to be common, this new ternary operator will be just as worthless as the old IIf function.

    Reply
  26. paulv

    Theodore: I just tried this in VS 2008 SP1 and I got the correct value of Nothing. If you’re still seeing this, I’d enter a bug at Microsoft Connect. Thanks!

    Reply

Leave a Reply