2

I want to know why the following line is not behaving correctly. as I use the IIF, although when the condition is True, the function returns getMessage

Return CType(IIf(Object.Equals(_newValue, _oldValue), 
             msg, GetMessage(msg)), PooMessage)

But the following lines behaves just fine:

If Object.Equals(_newValue, _oldValue) Then
        Return msg
Else
        Return CType(GetMessage(msg), PooMessage)
End If
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
Afflatus
  • 933
  • 1
  • 12
  • 39

2 Answers2

3

You should change from IIf() to If(), as the latter uses short-circuiting while the former does not. With the IIf() version, GetMessage() is being called even when the boolean evaluates to true, which might be causing side effects. When using If(), only the correct return value is evaluated:

Return CType(If(Object.Equals(_newValue, _oldValue), msg, GetMessage(msg)), PooMessage)

EDIT: Added sample code for better clarity of If() vs. IIF(), with dotnetfiddle example Fiddle: https://dotnetfiddle.net/vuMPgK

Code:

Imports System
Imports Microsoft.VisualBasic

Public Module Module1
    Public Sub Main()

        Dim didItWork as Boolean = False
        Dim myTestObject as Test = Nothing

        ' works, due to IF(). Only the 'true' value is calculated
        didItWork = If(myTestObject Is Nothing, False, myTestObject.MyValue)

            Console.WriteLine("Did If() work?: " & didItWork.ToString())


            ' does not work, due to IIF().  Both True and False conditions are calculated regardless of the original test condition.
            '  it fails because myTestObject is null, so trying to access one of its properties causes an exception.
            Try
                didItWork = IIF(myTestObject Is Nothing, False, myTestObject.MyValue)
                Console.WriteLine("Did IIF() work?: " & didItWork.ToString())
            Catch ex as Exception
                Console.WriteLIne("Error was thrown from IIF")
            End Try

    End Sub
End Module

Public Class Test
        Public Property MyValue as Boolean = True
End class
ps2goat
  • 8,067
  • 1
  • 35
  • 68
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Thank you @idle_Mind you got the problem right but I want to know why this phenomenon which you called short-circuiting happens. Could you a little but explain about that? – Afflatus Jan 20 '15 at 03:59
  • aah I get it now, because I am using reference type (referring to msg type) and because both sides of if conditions for true and false is being executed, the result will be the same. correct? – Afflatus Jan 20 '15 at 04:05
  • 1
    @Afflatus, I've added a code sample and a fiddle for a more simplified issue with `IIF()`. You should stay away from it as long as you are using a version of .NET that supports it. The only time you'll have to adjust your code is if your `IIF` clauses were returning different object types, such as a String for the true clause and an Integer for the false clause. (In that case, you can convert the integer using the `.ToString()` method, e.g.) – ps2goat Jan 20 '15 at 04:25
2

To clairify @Idle_Mind reason it is as follows...

r=IIF(x,y,z) 

is a function call. In order to call it all the parameters (x, y AND z) must be evaluated BEFORE it enters the function body for evaluation.

r=IF(x,y,z) 

is a Compiler directive. the components in your code that create "y" and "z" portions of what looks like a function call are not evaluated until AFTER the comparison is done on "x". If is effectively compiled as a full IF ELSE END IF structure like below...

if x then
    r=y
else
    r=z
end if

One neat thing to note is that whenever you see text in VB.Net that is colored like "Ctype" is coloured, it is a compiler directive instead of a traditional code unit.

DarrenMB
  • 2,342
  • 1
  • 21
  • 26