VB.NET – arrghh!

April 2, 2007

I get really annoyed when smarmy C# developers look down their noses at VB developers.

If I’m feeling like an argument I’ll ask them to write something in C# that I couldn’t replicate in VB. I’m not saying it’s impossible, but so far nobody has been able to do it (feel free to post a comment below if you’d like to try).

All of the Trade Me code is VB, and on the whole it does a perfectly good job. (btw, there is a good reason why we decided to migrate to VB rather than C#)

But, really, sometimes VB just doesn’t help itself.

Witness this recent email from Annie, one of the developers at Trade Me …

From: Annie
To: Development
Subject: Rounding numbers in VB.NET and SQL Server

Hey guys,I’ve just been debugging a situation in the sell process (for way too long) where two decimal numbers (9.5 and 10.5) were BOTH rounding to 10 by a call to exactly the same code: a simple call to good ol’ CLng.After searching around, it turns out that CLng, CInt, CByte, CCur and Round all implement what is known as “Banker’s Rounding” in VB.NET. This is also sometimes called “round to nearest”, or “round to even”. Basically, Banker’s rounding rounds 0.5 up sometimes and down other times. Apparently the convention is to round to the nearest EVEN number. Therefore, 1.5 and 2.5 would both round to 2. Likewise, 3.5 and 4.5 would both round to 4.If you’re interested, the rational behind this is that if you were rounding large sets of numbers, constantly rounding 0.5 UP would result in a bias as only 4 of 9 numbers (0.1, 0.2, 0.3 and 0.4) would cause a round DOWN and the remaining 5 numbers (0.5, 0.6, 0.7, 0.8 and 0.9) would cause a round UP.

ANYWAY, as you can imagine, this causes what seems to be slightly erratic un-deterministic behaviour to those of us who are used to “arithmetic rounding”. And unfortunately, it looks like there are quite a few calls to CLng particularly in the sell process. Calls to CLng are currently being used when checking for minimum or maximum values for attributes and eventually for storing and displaying integer values entered for said attributes. For example, if I enter 49.5m2 for the floor area of the apartment I’m trying to sell, it will round it up to 50m2. But if I enter 50.5m2, it will also round to 50m2. I dunno about you guys but I was always taught to round 0.5 UP in school, without exception. Anyhoo, some users might consider this to be a bug (I know I find it weird).

To add to the confusion, I just did a bit of a test in SQL Server and it looks like casting a decimal value to an int just truncates the number to the most precise digit (e.g. cast(10.9 as int) = 10).

So, basically just use a bit of caution when using CLng, CInt, CByte, CCur and Round in VB.NET and cast in SQL Server as they may be returning results quite different to what you’d expect, and worse yet, different results when calculated in the code as opposed to a stored proc.

Apparently Format and FormatNumber perform “arithmetic rounding” and although they spit out a string, in many of our cases these functions will do the trick as we tend to treat most of our integers in the sell process as strings anyway.

But yeah, just thought I’d share this with all of you. Please feel free to add to this discussion/rant.