What Was Wrong With #15?

Thursday, May 3, 2007

Not many takers on WWWTC #15, but Jason finally nailed it.

The bug in the code revolves around how VB allocates arrays. The following code snippet creates an array of 5 System.Char objects, and will output the number 5 to the screen, right?

Dim length As Integer = 5
Dim chars() As Char = New Char(length) {}


 The output is "6", which still astonishes those of us (me, at least) who hail from the land of semicolons. The number I pass to the New clause in VB doesn't specify the number of elements in the array, but the upper bounds of the array. Passing a 5 tells VB to create an array with 6 elements indexed 0 to 5.

I suspect this behavior is a compromise over the definition of an array's lower bound. Does an array start at 0? Does an array start at 1? It's a religious debate, but a VB developer could use the chars array like so:

For i As Integer = 0 To 4

... or like so:

For i As Integer = 1 To 5

... and neither will fail with an index out of bounds exception.

This behavior does cause a problem, however, when you want a precise number of characters and forget how New works. The unit test failed because it expected to get back a string with a length of 6 ("edoCoTedO"), but the actual string had a length of 7 (with a 0 character tacked on the end).

The fix is to create the array by passing the length of the string minus 1.

Eber Irigoyen Thursday, May 3, 2007
"Not many takers on WWWTC #15, but Jason finally nailed it."
try in C# next time =oP
Ben Reichelt Thursday, May 3, 2007
I do have to point out that the variable name of 'length' in the code snippet above adds to the confusion. If you named the variable 'upperBound' instead, I believe it would be more clear.

I'm not saying array lengths in vb aren't confusing (I stick to ArrayLists for this reason :), but there are ways to make the code more understandable.
Jason Thursday, May 3, 2007
The trick is to use the verbose syntax for declaring array dimensions in VB:

Dim chars() As Char = New Char(0 To length) {}

This is valid code so long as the lower bound is only ever zero, but to anyone reading the code it is now obvious where the problem is.
Joe Thursday, May 3, 2007
Of course, you can always make your intent more clear by using the form:

ReDim chars(0 To input.Length - 1)

It's a bit old school, I admit; but it probably documents itself a little better if the code might be reviewed by sharp-types.
Ken Friday, May 4, 2007
Prior to Visual Basic 2005 (where this is no longer supported), I put "Option Base 0" or "Option Base 1" at the top of all my code to force the array start and remind me what it is.
Aaron Wednesday, May 16, 2007
Oh its best when you are interoping with a co-worker who lives life as if the 0 base index starts at 1. Why do you send me nothing in the first element?
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!