Search code examples
arrayssortingtypesvbscriptmismatch

Type mismatch when returning an array


I'm writing a VBScript function, which takes as in put an array of strings and returns an array of the same strings sorted alphabetically. Ideally, I'd like this function to work exactly like (as an example) the uCase function, where you can say:

myString = ucase(mystring)

Where the value of "myString" will get replaced with the uppercase version of its contents.

But when I set up an array in my test script, then feed it to my sorting function, I get a type mismatch error assigning the result to the original variable. All I can figure is that VBScript must not allow you to overwrite an array with another array, because the TypeName function tells me that both the input variable I'm using and the output from the sorting function are the same type ("Variant()").

Here's my example code to give you something more concrete to work with:

Option Explicit
Dim testArray(), thisItem, sortedArray 
ReDim testArray(9)

testArray(0)="Xylophone"
testArray(1)="Elephant"
testArray(2)="Ferret"
testArray(3)="Eel"
testArray(4)="Dinosaur"
testArray(5)="Barracuda"
testArray(6)="Ape"
testArray(7)="Weasel"
testArray(8)="Firebird"
testArray(9)="Phoenix"

WScript.Echo "Starting Array:"
For Each thisItem In testArray
  WScript.Echo "  " & thisItem
Next

' This line will work fine, assigning Variant() to Empty sortedArray
sortedArray = SortArray(testArray)
' This line will generate a type mismatch, assigning Variant() to Variant()
testArray = SortArray(testArray)

WScript.Echo "Sorted Array:"
For Each thisItem In sortedArray
   WScript.Echo "  " & thisItem
Next

WScript.Quit 0

Function SortArray(ByVal inArray)

   Dim a, b, swapVal 

   For a = UBound(inArray) - 1 To 0 Step -1
      For b = 0 To a
         If inArray(b) > inArray(b+1) Then
            swapVal = inArray(b+1)
            inArray(b+1) = inArray(b)
            inArray(b) = swapVal
         End If
      Next
   Next

   SortArray = inArray

End Function 

If you run this example code as-is, you'll find that the line beginning with "sortedArray=" will work just fine. The line below that, beginning with "testArray=" will generate a type mismatch error.

Ideally, I'd like this function to operate such that EITHER or BOTH of those lines would work properly. (In other words, when I use it later I don't want to have to think "Oh yeah, I have to create another variable and assign the output to that instead of my original variable.")

Am I missing something or is VBScript incapable of doing what I want it to do here?


Solution

  • Short answer: Your Dim testArray() creates an abomination - a fixed array of no size that VBScript can't handle properly (just try to take its UBound()). Your script will work, if you delete those ().

    Beginning of a long answer: Look at this sample code:

    Option Explicit
    
    Dim aDyn : aDyn = Split("Xylophone Elephant Ferret Ape Weasel")
    WScript.Echo 0, "   aDyn:", Join(aDyn)
    Dim aDynCpy : aDynCpy = getSortedArray(aDyn)
    WScript.Echo 1, "aDynCpy:", Join(aDynCpy)
    WScript.Echo 2, "   aDyn:", Join(aDyn)
    
    Dim aFix(4) ' we want an optimized/non-growable fixed array
    Dim i
    For i = 0 To UBound(aFix)
        aFix(i) = aDyn(i)
    Next
    WScript.Echo 3, "   aFix:", Join(aFix)
    SortArray aFix ' sort in place/reserved memory
    WScript.Echo 4, "   aFix:", Join(aFix)
    
    aDynCpy = aDyn ' DYN: no problem
    WScript.Echo 5, "aDynCpy:", Join(aDynCpy)
    aDynCpy = getSortedArray(aFix) ' DYN: no problem
    WScript.Echo 6, "aDynCpy:", Join(aDynCpy)
    
    On Error Resume Next
    aFix = aDyn ' FIX: not possible
    WScript.Echo 7, Err.Description
    On Error GoTo 0
    
    WScript.Quit 0
    
    Function getSortedArray(ByVal inArray) ' let VBScript do the copy
      SortArray inArray ' sort copy in place
      getSortedArray = inArray
    End Function
    
    Sub SortArray(inArray) ' ByRef/Default, because we sort in place
       Dim a, b, swapVal
       For a = UBound(inArray) - 1 To 0 Step -1
          For b = 0 To a
             If inArray(b) > inArray(b+1) Then
                swapVal = inArray(b+1)
                inArray(b+1) = inArray(b)
                inArray(b) = swapVal
             End If
          Next
       Next
    End Sub
    

    output:

    cscript X6971815.vbs
    0    aDyn: Xylophone Elephant Ferret Ape Weasel
    1 aDynCpy: Ape Elephant Ferret Weasel Xylophone
    2    aDyn: Xylophone Elephant Ferret Ape Weasel
    3    aFix: Xylophone Elephant Ferret Ape Weasel
    4    aFix: Ape Elephant Ferret Weasel Xylophone
    5 aDynCpy: Xylophone Elephant Ferret Ape Weasel
    6 aDynCpy: Ape Elephant Ferret Weasel Xylophone
    7 Type mismatch
    

    to get a feeling for how to deal with fixed/dynamic arrays wrt to copy vs. in-place modification. Fixed arrays - that can't be 'overwritten' - should be sorted in place/their reserved memory; all arrays can be copied into a dynamic one.

    Masochists may look at this disgusting discussion