One of my all time favorite features in C# and CPP has been the conditional operator (?:). The brevity and elegance introduced by this operator in the code is unparalleled. We had IIF in all the previous versions of VB.net, which was not an operator in the true sense (It was a call to a function). But now with Visual Studio 2008, we have taken an "i" from this function and promoted it to operator status. "IF" can now be used instead of "IIF". It provides full functionality of the IIF function with some very interesting additions of its own, including short-circuiting. It even comes in two flavors: the ternary flavor which mimics the functionality of the IIF function while adding some more to it, and the binary flavor which introduces a new sort of comparison/assignment. Before I start getting too vague, I will just delve into the details of how to use the greatness called the IF operator!
Note: I will touch only the ternary flavor in this blog, and will follow up with the binary if operator and other interesting examples for if in blogs to come.
The first and most basic use of IF is the universal "compare, choose and assign" which is the functionality of conditional operators, and the iif function. The following are the definitions of the three operands of IF(TestExpression, TruePart, FalsePart):
- TestExpression, is any expression that produces a boolean value or a value convertible to boolean. With option strict on the expression needs to produce a value that is either boolean or has a widening conversion to boolean.
- TruePart, is the return value of the IF operator if the test expression above evaluates to true. Note that the return type of the operator is decided based on the wider of the types of the truepart and the falsepart, e.g, if the truepart is an integer and the falsepart is a decimal, then decimal which is the wider of the two types will be the return value’s type. For details on type conversions and for a list of wider and narrower types, please refer here
- FalsePart, is the return value of the IF operator if the test expression evaluates to false. Here in lies the short-circuiting. If the test expression evaluates to true, the FalsePart is just ignored. The compiler will not touch it. It will not evaluate it. So as long as your test expression is true, you can do null references here, call functions on objects that do not actually exist, or anything that the parser will let you get away with. It will just not be evaluated. (Please do not think that I am recommending you to do any of the afore-mentioned evils, but as long as your test expression remains true you can get away with this). This can be very useful while calling a function on a variable which may not be instantiated, You can simply do:
Dim return = If(var Is Nothing, foo1(), var.foo())
Now lets look at some code that shows the ternary flavor of the IF operator
Module Module1 Public Class Number Private _RealPart As Double Public Property RealPart() As Double Get Return _RealPart End Get Set(ByVal value As Double) _RealPart = value End Set End Property Private _ComplexPart As Double Public Property ComplexPart() As Double Get Return _ComplexPart End Get Set(ByVal value As Double) _ComplexPart = value End Set End Property Public Sub New(ByVal pRealPart As Double, Optional ByVal pComplexPart As Double = 0.0) _RealPart = pRealPart _ComplexPart = pComplexPart End Sub Public Overrides Function ToString() As String Return If(_ComplexPart = 0.0, _RealPart.ToString(), _ _RealPart.ToString & " + " & _ComplexPart.ToString() & "i") End Function End Class Sub Main() Dim i As New Number(1) 'The If operator looks checks the number to see if it is real or complex, and prints accordingly Dim NumberPrinter = Function(arg As Number) arg.RealPart.ToString & " + " & arg.ComplexPart.ToString() & "i" Console.WriteLine("i is a real number:") Console.WriteLine(If(i.ComplexPart = 0.0, i.RealPart.ToString(), NumberPrinter(i))) 'Or the If operator can be moved inside the lambda to add to the elegance Dim j As New Number(1, 2) Dim NumberPrinter2 = Function(arg As Number) If(arg.ComplexPart = 0.0, arg.RealPart.ToString(), _ arg.RealPart.ToString & " + " & arg.ComplexPart.ToString() & "i") Console.WriteLine("j is a complex number:") Console.WriteLine(NumberPrinter2(j)) 'You can also use the short-circuiting feature of the if operator Dim k As Number Console.WriteLine("k does not have any value, so we print j again:") Console.WriteLine(If(k Is Nothing, j.ToString, k.ToString)) k = New Number(3, 4) Console.WriteLine("And now for k with a value:") Console.WriteLine(If(k Is Nothing, j.ToString, k.ToString)) End Sub End Module
Notice how short-circuiting is used in the above code when k does not have a value (the first call). The call to a method from a null object is never evaluated.
For those addicted IIF users wondering if they can still use the legacy IIF function in Orcas, the answer is yes. We still support IIF, but with all the amazing things that you can do with the IF operator, why would you want to keep on typing those extra "i"s? And while you explore the many, many things that you can do with IF, I will be writing and posting more IF code and then some more! Until then,
Dim blog_next = If(bIFoundMoreInterestingScenarios, blogDelvingIntoIF, blogUnknown)
If you know what I mean 🙂