Friday, October 27, 2006

Things that Don't Suck and Things that Do

Since I sometimes worry that my blog is turning into a gripelog, I'd like to highlight a very positive experience I recently had with a company. I wanted to buy some decent desk chairs for my apartment, and due to getting a higher-than-average computer desk, I needed chairs that were fairly tall (seats around 30" from the floor).

I finally converged on a lab-stool that I found at and placed an order for two instances of it. They arrived a few weeks later in boxes with fairly simple assembly instructions. Unfortunately, and here's where it gets interesting, one of the chairs was broken -- the ring of plastic that was supposed to secure the foot-rest to the chair's main support was broken. After I sent an email describing the problem to their support address, they said that all I needed to do was take a picture of the broken part and they'd mail out a replacement. A few weeks later, the replacement arrived and I was able to assemble the second chair. They even were very polite when I bugged them about why the part hadn't arrived when it already had (UPS apparently didn't leave a notice for me). All in all, I was quite impressed with this company and I'd definitely buy from them again if I needed more chairs.

So, now on to less happy things. People with a mathematical background are familiar with the principle of transitivity; basically, this says that if A is less than B and B is less than C, then A is less than C. This isn't just an arcane mathematical property, though; it has important practical consequences. For instance, if you want to quickly find a word in a list of words, having the words in sorted order is a huge benefit. You can do this because, among other things, the "less-than" relationship between words is transitive (without transitivity, even the idea of a "sorted order" is somewhat peculiar).

Why do I mention this? Well, because in C#, the following inequality holds:

"Y-" < "Y'" < "-Y-" < "Y-"

That's right: by default, Microsoft's C# implementation compares strings in a non-transitive manner, contrary to all expectations that any sane programmer would have. This bit me yesterday, when I was trying to sort a rather large array of strings and then perform searches in the array. Words that I knew perfectly well were in the array (I could even see them in the debugger!) weren't being found by the search. Why? Because the list wasn't in sorted order, even after calling Array.Sort() on it. Why? Because (see above) there is no such thing as a sorted order using the default C# comparator!

At first, I hoped this might just be a bug. But in the manual, I found a nice little explanation that the default sort doesn't perform a standard lexicographic comparison, in an attempt to provide a more "human-friendly" sorting. (they give the example of sorting "coop" next to "co-op", which confuses me since those two sort next to each other in any even. But whatever.) Instead, you have to use a method which is confusingly called "CompareOrdinal" instead of "DontSuckCompare".

Of course, after reading this, I guess nothing Microsoft does can really surprise me any more. Interestingly, Mono doesn't seem to have copied this particular "bug" (although I only tested one case with it). I don't know if this is good or bad: after all, it's probably only a matter of time before a piece of software that unintentionally depends on .NET's weird string comparisons comes into being.