Type mismatch when returning an array

msalsbury picture msalsbury · Jun 6, 2013 · Viewed 13.4k times · Source

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?

Answer

Ekkehard.Horner picture Ekkehard.Horner · Jun 6, 2013

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