Overloading Methods and More in VBScript

Many programming languages, such as Java or C, allow you to create overloaded methods and allow optional parameters for your methods. This ability has been removed from VB’s Scripting Edition; however, today I’m going to show you some coding techniques that will allow you to regain some of this functionality.

To begin, let’s define what an overloaded method (constructor) really is.  Quite simply, overloading is the process of creating multiple instances of a method or function with the same name that accept different inputs and offer different outputs.  Programming languages that adhere to strict data types employ overloading to allow similar functions to work on different data types.

public double square(double number)

{

   return number * number;

}

 

public float square(float number)

{

   return number * number;

}

In Java, for example, a constructor (basically, a function) is defined by its input and output types as well as its name.  So let’s assume you wanted to write a function that would output the square of a number.  It might accept a double type as an input, so naturally it would also output a double.  You might also want to create the same function again to work with floating point numbers.  This second instance would be the overloaded constructor.

This, of course, isn’t possible in VBScript because function and subroutine names must be unique.  I suppose constructor overloading wasn’t deemed necessary since all variables in VBS are of type Variant anyway.

{mospagebreak title=Information Overload}

Despite the fact that constructor overloading has been removed from VBScript, you can simulate much of its functionality.  This involves determining the type of data being passed into the function and responding accordingly.  From my experience, this is most often useful when you have a function that can be performed against a single target or against multiple targets in an array.  Let’s consider an example.

Function PingTest(varTarget)

   arrResults = Array()

   ReDim Preserve arrResults(i)

   strComputer = "."

   Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")

   Set colPings = objWMIService.ExecQuery("Select * From Win32_PingStatus " _

       & "Where Address = ‘" & varTarget & "’")

   For Each objPing In colPings

       If objPing.StatusCode = 0 Then

          arrResults(i) = "Success"

       Else

          arrResults(i) = "Failure"

       End If

   Next

   PingTest = arrResults

End Function

This code sample defines a function called PingTest.  It accepts a string input (an IP address) and performs a ping test.  The result of that test is returned in an array.

I’ve chosen to return results in an array, because I’ll be adding multiple results later in this article.

The exact mechanics of this function are irrelevant as far as our topic is concerned, so I’ll be brief.  The IP address (as a string) is used in a query to the Win32_PingStatus WMI class.  This class returns a status code that indicates the result of a ping test.  We then return the word “success” or “failure” based upon that status.

All is well.  However, this function can only be run against a single machine at any given time.  What if we wanted to supply an array of targets and receive all of the results at the same time?  An overloaded constructor would be nice.  But since we cannot create one, let’s take a look at what we can do instead.

As I mentioned earlier, all variable types in VBS are treated as type Variant.  This means that our function doesn’t particularly care whether we provide a string or an array as a parameter.  It’s only written to work with a string.  Thus, we can pass any data type we wish.  All we need to do is rewrite our function to work with different data types.

{mospagebreak title=Using the Overloaded Constructor}

Function PingTest(varTarget)

   If IsArray(varTarget) Then

       ‘Test against an array

       PingTest = arrResults

   Else

       ‘Test against a string

       PingTest = arrResults

   End If

End Function

You can see here that I’ve changed the logic of this function a bit.  Namely, I’m using the IsArray function along with a simple IF statement to determine exactly what type of data was passed into the function.  Now I can insert the code to handle each case.

Function PingTest(varTarget)

   If IsArray(varTarget) Then

       arrResults = Array()

       For i = 0 To UBound(varTarget)

          ReDim Preserve arrResults(i)

          strComputer = "."

          Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")

          Set colPings = objWMIService.ExecQuery("Select * From Win32_PingStatus " _

              & "Where Address = ‘" & varTarget(i) & "’")

          For Each objPing In colPings

              If objPing.StatusCode = 0 Then

                 arrResults(i) = "Success"

              Else

                 arrResults(i) = "Failure"

              End If

          Next

       Next

       PingTest = arrResults

   Else

       arrResults = Array()

       ReDim Preserve arrResults(i)

       strComputer = "."

       Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")

       Set colPings = objWMIService.ExecQuery("Select * From Win32_PingStatus " _

          & "Where Address = ‘" & varTarget & "’")

       For Each objPing In colPings

          If objPing.StatusCode = 0 Then

              arrResults(i) = "Success"

          Else

              arrResults(i) = "Failure"

          End If

       Next

       PingTest = arrResults

   End If

End Function

Okay, this looks pretty complicated, but it’s really not as bad as it seems.  If you look closely, each branch of this IF block is identical to my original function, with one minor change in the If portion.  Here I’ve wrapped my function code inside of a For Each loop that moves through each IP address in the supplied array.  Each test’s result is added to the output array before it is returned by the function.  The Else portion remains the same as in the original function because it uses a string parameter as originally intended.

Okay, so now that we’ve created an “overloaded” constructor, how do we use it in our scripts?  Well, let’s take a look.  First, let’s see it the way we wrote it the first time.

arrResults = PingTest("127.0.0.1")

WScript.Echo arrResults(0)

This example performs a ping test against the local loopback address.  It should simply print “Success” on the screen.

arrTests = Array("127.0.0.1", "192.168.0.0", "192.168.0.100")

arrResults = PingTest(arrTests)

For i = 0 To UBound(arrTests)

   WScript.Echo arrTests(i) & ": " & arrResults(i)

Next

Here I’m supplying an array of strings to test against.  The PingTest function still returns an array of results so it’s a simple matter of iterating through that array.  Each element in the results array matches the same element in the tests array.  Thus, the result for the test on arrTests(0) can be found in arrResults(0).

{mospagebreak title=Implementing Optional Parameters}

Many programming languages also offer the ability to add optional parameters to your functions.  Full VB allows this by using the Optional keyword, but as with many features this was removed from the Scripting Edition.  Here again, I have a cool little workaround that you may find useful.

Essentially, an optional parameter is one that may or may not be included when calling a function or subroutine.  If omitted, this value will generally revert to a default value.  Let’s begin with our original ping function again.

Function PingTest(strTarget, intTests)

   arrResults = Array()

   For i = 0 To intTests – 1

       ReDim Preserve arrResults(i)

       strComputer = "."

       Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")

       Set colPings = objWMIService.ExecQuery("Select * From Win32_PingStatus " _

          & "Where Address = ‘" & strTarget & "’")

       For Each objPing In colPings

          If objPing.StatusCode = 0 Then

              arrResults(i) = "Success"

          Else

              arrResults(i) = "Failure"

          End If

       Next

   Next

   PingTest = arrResults

End Function

Here, I’ve changed the PingTest function.  It accepts a single string value for an IP address, but it also accepts an integer number of tests.  The addition of a For loop allows me to perform the specified number of tests over and over against the same IP address.  That is simple enough, but suppose that I don’t want to have to specify that integer value every time I call this function.  If the value is omitted, I want the function to perform a single test; otherwise, perform the number provided.

Function PingTest(strTarget, intTests)

   If IsNull(intTests) Then intTests = 1

 

   arrResults = Array()

To accomplish this, I only need to insert a single line at the beginning of my function.  This simply tests the intTests value, and if it is Null, it sets it to a default value.

arrResults = PingTest("127.0.0.1", Null)

For i = 0 To UBound(arrResults)

   WScript.Echo arrResults(i)

Next

This is how to use the function.  As you can see, the first parameter requires a string IP address.  The second may contain an integer or a Null value.  Then it’s just a matter of working through the array that is returned.

arrResults = PingTest("127.0.0.1", Null)

arrResults = PingTest("127.0.0.1", 3)

The function above can be called by either supplying a Null value or an actual integer.  While not completely identical to an optional value, it does allow for some of the same usage.

As you can see, there are a few ways to improve your functions to regain some of the missing functionality that was removed from VBScript.  I hope that you find these tips helpful.  So, go ahead and experiment.  See how these new ways of creating functions can improve your applications.  Until next time, keep coding!

One thought on “Overloading Methods and More in VBScript

  1. Man this is a ugly way to make an overload method.
    Sometimes you need to face the truth:
    VBSCRIPT do not have overload method 🙂

[gp-comments width="770" linklove="off" ]