What Was Wrong With #15?

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) {}


Console.WriteLine(chars.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
    Console.WriteLine(chars(i))
Next

... or like so:

For i As Integer = 1 To 5
    Console.WriteLine(chars(i))
Next

... 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.

posted on Wednesday, May 02, 2007 9:12 PM by scott

Comments

Wednesday, May 02, 2007 6:52 PM by Eber Irigoyen

# re: What Was Wrong With #15?

"Not many takers on WWWTC #15, but Jason finally nailed it."
try in C# next time =oP
Thursday, May 03, 2007 6:19 AM by Ben Reichelt

# re: What Was Wrong With #15?

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.
Thursday, May 03, 2007 7:08 AM by Jason

# re: What Was Wrong With #15?

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.
Thursday, May 03, 2007 7:52 AM by Joe

# re: What Was Wrong With #15?

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.
Thursday, May 03, 2007 7:23 PM by Christopher Steen

# Link Listing - May 3, 2007

ASP.Net Ajax, Performance and Race Conditions, Oh MY! [Via: Ayende Rahien ] Updated BizTalk Resources...
Friday, May 04, 2007 11:42 AM by Ken

# re: What Was Wrong With #15?

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.
Tuesday, May 15, 2007 8:06 PM by Aaron

# re: What Was Wrong With #15?

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?