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.

Print | posted @ Thursday, May 03, 2007 1:12 AM

Comments on this entry:

Gravatar # re: What Was Wrong With #15?
by Eber Irigoyen at 5/3/2007 1:52 AM

"Not many takers on WWWTC #15, but Jason finally nailed it."
try in C# next time =oP
  
Gravatar # re: What Was Wrong With #15?
by Ben Reichelt at 5/3/2007 1:19 PM

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.
  
Gravatar # re: What Was Wrong With #15?
by Jason at 5/3/2007 2:08 PM

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.
  
Gravatar # re: What Was Wrong With #15?
by Joe at 5/3/2007 2:52 PM

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.
  
Gravatar # re: What Was Wrong With #15?
by Ken at 5/4/2007 6:42 PM

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.
  
Gravatar # re: What Was Wrong With #15?
by Aaron at 5/16/2007 3:06 AM

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?
  

Your comment:

Title:
Name:
Email:
Website:
 
Italic Underline Blockquote Hyperlink
 
 
Please add 8 and 8 and type the answer here: