Search code examples
arraysvb.netmethodsparameter-passingsubroutine

Passing array variables and other variables in and out of VB.Net Subroutine methods


I am in the process of transcribing code, which manipulates arrays of complex numbers, from VB 6 to VB.Net form. The language syntax has become more strict and I have studied the use of the ByVal and ByRef keywords quite carefully so that I can either not change or change the variables passing through the method subroutine as I require. However it seems that VB 6 used to allow me to pass null variables into the subroutine and to receive changed (internally calculated) variables back in the call line. VB.Net does not seem to allow null variables to be passed into a method subroutine as a rule? In the code snippet that I share below I can only avoid invoking a null exception by arbitrarily setting initial values to parameters that are actually really defined in the method subroutine. Is there a way to avoid this inelegant overhead?

    Module Module1
    Sub Main()
        Dim Sx As Double() = {-0.0053, 0.8882, 0.8882, -0.0053}
        Dim Sy As Double() = {-0.0102, -0.4594, -0.4594, -0.0102}
        Dim Tx As Double() = {1.0, 1.0, 1.0, 1.0} 'To be calculated by method Stot and passed back to Main!
        Dim Ty As Double() = {1.0, 1.0, 1.0, 1.0} 'To be calculated by method Stot and passed back to Main!
        Stot(Sx, Sy, Tx, Ty) '[STh]--->[TTh]
        Console.WriteLine(Tx(0))
        Console.WriteLine(Ty(0))
        Console.WriteLine(Tx(1))
        Console.WriteLine(Ty(1))
        Console.WriteLine(Tx(2))
        Console.WriteLine(Ty(2))
        Console.WriteLine(Tx(3))
        Console.WriteLine(Ty(3))
        Stop
    End Sub
    Public Sub Stot(ByVal Sx As Double(), ByVal Sy As Double(), ByRef Tx As Double(), ByRef Ty As Double())
        Dim AA As Double
        Dim BB As Double
        Dim C As Double
        Dim D As Double
        Call Cmult(Sx(0), Sy(0), Sx(3), Sy(3), AA, BB)
        Call Cdiv(AA, BB, Sx(1), Sy(1), C, D) '(S11*S22)/S21
        Tx(0) = Sx(2) - C 'S12-((S11*S22)/S21)
        Ty(0) = Sy(2) - D
        Call Cdiv(Sx(0), Sy(0), Sx(1), Sy(1), Tx(2), Ty(2)) 'T12=S11/S21
        Call Cdiv(Sx(3), Sy(3), Sx(1), Sy(1), Tx(1), Ty(1)) 'T21=S22/S21
        Tx(1) = -1 * Tx(1) 'T21=-1*(S22/S21)
        Ty(1) = -1 * Ty(1)
        Call Cdiv(1, 0, Sx(1), Sy(1), Tx(3), Ty(3)) 'T22=1/S21
    End Sub
    Public Sub Cdiv(ByVal X1 As Double, ByVal Y1 As Double, ByVal X2 As Double, ByVal Y2 As Double, ByRef X3 As Double, ByRef Y3 As Double)
        Dim Denom As Double
        Denom = X2 * X2 + Y2 * Y2 'Multiplication by conjugate (X2+iY2)(X2-iY2)
        X3 = (X1 * X2 + Y1 * Y2) / Denom
        Y3 = (Y1 * X2 - X1 * Y2) / Denom
    End Sub
    Public Sub Cmult(ByVal X1 As Double, ByVal Y1 As Double, ByVal X2 As Double, ByVal Y2 As Double, ByRef X3 As Double, ByRef Y3 As Double)
        X3 = X1 * X2 - Y1 * Y2
        Y3 = X1 * Y2 + Y1 * X2
    End Sub
End Module

The subroutine StoT is converting a matrix of S Parameters into a matrix of T Parameters: a common microwave engineering task. What it is doing is not important it merely serves as an example: how to code this form of data-sharing in VB.Net is the important point. This console app is defining the array parameters as Double(): arrays of double-precision numbers - a separate array for X and Y components of complex numbers (in the Main method). I understand that arrays are automatically accorded the reference type in VB.Net so there is no need to define the passed parameters as ByVal or ByRef in the called sub-routine: StoT. Again I repeat: I could only make this call work without invoking a null exception within StoT by pre-defining arbitrary values for the output parameters Tx() and Ty() in the Main Definitions. In order to accomplish the required arithmetic tasks the method StoT needs to perform complex division and complex multiplication tasks which are coded in method subroutines: CDiv() and CMult(). Again these take in and provide output double-precision numbers following the rule that numbers can only be provided as output numbers using the ByRef keyword. However these calls do not invoke a null exception even though they generate an answer complex number that is not pre-existing. So my question is why is this. There seems to be an inconsistency....


Solution

  • I have long forgotten whether this worked differently in VB6, but in .NET when you pass an Array ByRef, you can assign the argument to a completely different array in the called method. So if you pass in Nothing, you can allocate a new Array and assign the new Array to the ByRef argument. Like this:

    Module Module1
        Sub Main()
            Dim Sx As Double() = {-0.0053, 0.8882, 0.8882, -0.0053}
            Dim Sy As Double() = {-0.0102, -0.4594, -0.4594, -0.0102}
            Dim Tx As Double() = Nothing '{1.0, 1.0, 1.0, 1.0} 'To be calculated by method Stot and passed back to Main!
            Dim Ty As Double() = Nothing '{1.0, 1.0, 1.0, 1.0} 'To be calculated by method Stot and passed back to Main!
            Stot(Sx, Sy, Tx, Ty) '[STh]--->[TTh]
            Console.WriteLine(Tx(0))
            Console.WriteLine(Ty(0))
            Console.WriteLine(Tx(1))
            Console.WriteLine(Ty(1))
            Console.WriteLine(Tx(2))
            Console.WriteLine(Ty(2))
            Console.WriteLine(Tx(3))
            Console.WriteLine(Ty(3))
            Stop
        End Sub
        Public Sub Stot(ByVal Sx As Double(), ByVal Sy As Double(), ByRef Tx As Double(), ByRef Ty As Double())
            Dim AA As Double
            Dim BB As Double
            Dim C As Double
            Dim D As Double
    
            If IsNothing(Tx) Then
                Tx = New Double() {1.0, 1.0, 1.0, 1.0}
            End If
            If IsNothing(Ty) Then
                Ty = New Double() {1.0, 1.0, 1.0, 1.0}
            End If
    
            Call Cmult(Sx(0), Sy(0), Sx(3), Sy(3), AA, BB)
            Call Cdiv(AA, BB, Sx(1), Sy(1), C, D) '(S11*S22)/S21
            Tx(0) = Sx(2) - C 'S12-((S11*S22)/S21)
            Ty(0) = Sy(2) - D
            Call Cdiv(Sx(0), Sy(0), Sx(1), Sy(1), Tx(2), Ty(2)) 'T12=S11/S21
            Call Cdiv(Sx(3), Sy(3), Sx(1), Sy(1), Tx(1), Ty(1)) 'T21=S22/S21
            Tx(1) = -1 * Tx(1) 'T21=-1*(S22/S21)
            Ty(1) = -1 * Ty(1)
            Call Cdiv(1, 0, Sx(1), Sy(1), Tx(3), Ty(3)) 'T22=1/S21
        End Sub
        Public Sub Cdiv(ByVal X1 As Double, ByVal Y1 As Double, ByVal X2 As Double, ByVal Y2 As Double, ByRef X3 As Double, ByRef Y3 As Double)
            Dim Denom As Double
            Denom = X2 * X2 + Y2 * Y2 'Multiplication by conjugate (X2+iY2)(X2-iY2)
            X3 = (X1 * X2 + Y1 * Y2) / Denom
            Y3 = (Y1 * X2 - X1 * Y2) / Denom
        End Sub
        Public Sub Cmult(ByVal X1 As Double, ByVal Y1 As Double, ByVal X2 As Double, ByVal Y2 As Double, ByRef X3 As Double, ByRef Y3 As Double)
            X3 = X1 * X2 - Y1 * Y2
            Y3 = X1 * Y2 + Y1 * X2
        End Sub
    End Module