Previous | Index | Next 

[PRB] Default member isn’t resolved for arguments of IIF and Choose methods

In the vast majority of cases, the IIF and Choose methods are used with scalar values, such as strings and numbers, as in:

        Dim v as Variant
        v = IIF(EvaluateTest(), "Test is true", "Test is false")
        v = Choose(EvaluateIndex(), 2, 4, 8, 16)

However, these methods also take object values, as this code snippet demonstrates

        Dim v as Variant
        Set v = IIF(True, New Collection, Nothing)
        Debug.Print TypeName(v)   ' => displays "Collection"

When the original VB6 code passes object variable – for example, a TextBox control or an ADODB.Field object - to either the IIF or Choose methods, VB Migration Partner can’t automatically append the default member, because the developer might mean to pass and receive the object reference, not its default member. For example, the following VB6 code:

        Function GetText(ByVal tb1 As TextBox, ByVal tb2 As TextBox) As String
            GetText = IIf(tb1 Is Nothing, tb2, tb1)
        End Function

is incorrectly translated to VB.NET as

        Function GetText(ByVal tb1 As VB6TextBox, ByVal tb2 As VB6TextBox) As String
            GetText  = IIf(tb1 Is Nothing, tb2, tb1)
        End Function

instead of

        Function GetText(ByVal tb1 As VB6TextBox, ByVal tb2 As VB6TextBox) As String
            GetText = IIf(tb1 Is Nothing, tb2.Text, tb1.Text)
        End Function

A future version of VB Migration Partner might fix this problem automatically. In the meantime, there are a couple techniques that you can use as a workaround.

First, you can use a PreProcess pragma to replace all the occurrences of IIf and Choose methods with calls to special methods named Scalar_IIf and Scalar_Choose. The pragma can have project-level visibility (in which case it must be stored in a *.pragmas file) or file-level visibility:

        '## PreProcess "\bIIf\(", "Scalar_$0", True
        '## PreProcess "\bChoose\(", "Scalar_$0", True

You can also merge the two pragmas, as follows:

        '## PreProcess "\b(IIf|Choose)\(", "Scalar_$0", True

VB Migration Partner recognizes these two special Scalar_*** functions and correctly resolves the default member of object variables passed as arguments to the IIf and Choose methods.

If you are one hundred percent sure that you never used the IIf and Choose methods to assign objects, the previous pragmas work quite nicely. However, if you aren’t sure, you might want to use a more complex regular expression, that affects only simple assignments and doesn’t modify Set statements:

        '## PreProcess "(?<=\n\s*(Let\s+)?\S+\s*=\s*)(IIf|Choose)\(", "Scalar_$0", True

However, please notice that this pragma works only for direct assignments (using an implicit or explicit Let keyword) and fails to perform the replacement when the IIf and Choose methods appear inside expression or as arguments to method calls.

The second technique that is available to work around this issue is using the special IIf6 and Choose6 functions, that are available in the VisualBasic6_Support.bas module as well as in VB Migration Partner’s support library. The peculiarity of these special functions is that they are able to evaluate the default member of objects passed to them. To see why this feature can be useful, consider the following case:

        Function GetControlText(ByVal ctrl As Control) As String
            ' return the default property of a control, or an empty string 
            GetControlText = IIf(ctrl Is Nothing, "", ctrl)
        End Function

In this case, the trick based on the Scalar_IIf special method doesn’t work, because VB Migration Partner wouldn’t know how to generate the default member of the ctrl parameter, because the parameter is late-bound. The solution is including the VisualBasic6_Support.bas module to the current project and edit the line as follows:

        GetControlText = IIf6(ctrl Is Nothing, "", ctrl)

If you are sure that all the IIf and Choose methods in the project return a scalar value, you can avoid including the VisualBasic6_Support.bas module and perform a post-migration replacement with the following pragma:

        '## project:PostProcess "\b(?<fn>IIf|Choose)\b", "${fn}6", True

 

Previous | Index | Next