Comment commentary

A recent highly-voted-up question on Programmers asked what’s wrong with comments that explain complex code? I think quite a bit about how I comment my code but rather than posting an answer on Programmers I thought I’d blog about it a bit here. I already discussed this topic — HOLY GOODNESS TEN YEARS AGO wow I have been writing this blog for a long time —  and everything I said then still applies. But today thanks to Roslyn being open-sourced there is now a large corpus of my code on the internet so I can talk about my comment strategy in the context of real production code. Continue reading

Real world async/await defects

Today I’m once again asking for your help.

The headliner feature for C# 5 was of course the await operator for asynchronous methods. The intention of the feature was to make it easier to write asynchronous programs where the program text is not a mass of inside-out code that emphasizes the mechanisms of asynchrony, but rather straightforward, easy-to-read code; the compiler can deal with the mess of turning the code into a form of continuation passing style.

However, asynchrony is still hard to understand, and making methods that allow other code to run before their postconditions are met makes for all manner of interesting possible bugs. There are a lot of great articles out there giving good advice on how to avoid some of the pitfalls, such as:

These are all great advice, but it is not always clear which of these potential defects are merely theoretical, and which you have seen and fixed in actual production code. That’s what I am very interested to learn from you all: what mistakes were made by real people, how were they discovered, and what was the fix?

Here’s an example of what I mean. This defect was found in real-world code; obviously the extraneous details have been removed:

Frob GetFrob()
{
  Frob result = null;
  var networkDevice = new NetworkDevice();
  networkDevice.OnDownload += 
    async (state) => { result = await Frob.DeserializeStateAsync(state); };
  networkDevice.GetSerializedState(); // Synchronous
  return result; 
}

The network device synchronously downloads the serialized state of a Frob. When it is done, the delegate stored in OnDownload runs synchronously, and is passed the state that was just downloaded. But since it is itself asynchronous, the event handler starts deserializing the state asynchronously, and returns immediately. We now have a race between GetFrob returning null, and the mutation of closed-over local result, a race almost certainly won by returning null.

If you’d rather not leave comments here — and frankly, the comment system isn’t much good for code snippets anyways — feel free to email me at eric@lippert.com. If I get some good examples I’ll follow up with a post describing the defects.

What are the fundamental rules of pointers?

A lot of questions I see in the C tag on StackOverflow are from beginners who have never been taught the fundamental rules of pointers. (I note that these rules apply to C# as well, though it is rare to use raw pointers in C#.) A lot of introductions to pointers get caught up on the implementation details of what pointers are for a particular compiler targeting a particular architecture, so I want to be a bit more abstract than that. So, without further ado, here are the fundamentals: Continue reading

Find a simpler problem

A very common unanswerable question I see on StackOverflow is of the form “my CS homework assignment is to solve problem X and I don’t even know how to get started. How do I get started?” That’s too vague and unfocussed for a site like StackOverflow, which is for specific technical questions that have specific answers.

My recent post on the similarly vague problem of how to debug small programs has gotten a lot of hits and great comments; thanks all for that. In light of that I thought I might do an irregular series each highlighting some basic problem-solving techniques for beginner programmers, CS students and the like.(Of course these apply to expert programmers too, but expert programmers often already know these techniques.) So, how do you get started?
Continue reading

How to debug small programs

One of the most frequent categories of bad questions I see on StackOverflow is:

I wrote this program for my assignment and it doesn’t work.
[20 lines of code].

And… that’s it.

If you’re reading this, odds are good it’s because I or someone else linked here from your StackOverflow question shortly before it was closed and deleted. (If you’re reading this and you’re not in that position, consider leaving your favourite tips for debugging small programs in the comments.)

StackOverflow is a question-and-answer site for specific questions about actual code; “I wrote some buggy code that I can’t fix” is not a question, it’s a story, and not even an interesting story. “Why does subtracting one from zero produce a number that is larger than zero, causing my comparison against zero on line 12 to incorrectly become true?” is a specific question about actual code. Continue reading

Maybe there’s something wrong with the universe, but probably not

No kidding, I was just walking down a hallway in my building when I overhead the following quite loud conversational fragment through an open doorway:

Angry woman’s voice: “Why are you in the ladies room?! You are the third man to… oh no.”

Like Hobbes, it’s the moment of dawning comprehension that I live for – the exact moment when she realized that she, not everyone else, was in the wrong room was readily apparent. (One wonders what the first two gentlemen did, since clearly they did not successfully disabuse the lady of her error.) Since the building across the courtyard from mine has a mirror-imaged layout, this is a very easy mistake to make if you are visiting from the other building.

I contrast that moment of dawning comprehension with Dr. Crusher’s similar moment in that memorable 1990 episode when she realizes that she’s not crazy, it’s the entire universe that is wrong. When faced with an absurd and unexpected situation – the gradual disappearance of first the crew and then the entire universe – she at least considers that she’s the crazy one.

Unlike most people, I encounter compiler and library bugs all day long in my job, though mostly ones that I caused in the first place. (Sorry!) But even still, when I am writing “normal” code (rather than test cases designed to break the compiler or regress previous bugs), I try to ensure that my attitude upon encountering an unexpected situation is that I’m the crazy one. Usually it’s my code that is wrong, or my misunderstanding the output, rather than a compiler or library bug.

As the authors of The Pragmatic Programmer point out in their third chapter, “select() isn’t broken” – if you are writing perfectly normal code then odds are good you are not the first person to discover what should be an obvious problem in a well-tested product. If you think you’ve found a bug in the math library, maybe you have. Or maybe you’ve actually passed radians to a method that takes degrees, or forgotten to take floating point rounding error into account, or some other such thing. The more obvious the problem, the more likely it is that you’re the crazy one. If the code doesn’t compile and you think it should, it could be a bug in the compiler. But read the error message carefully; it is probably telling you what is wrong with the code.

If you think you’ve found a C# compiler bug, please, by all means bring it to our attention; post it on Connect, or have the community take a gander at it via StackOverflow or one of the Microsoft forums. There certainly are bugs in the compiler and the more we get good information on, the better. Including a small-but-complete program that reproduces the problem and the version number of the compiler you’re using is a big help. But first, do stop and take a good hard look at the code and think about whether it is more likely to be a problem with the code or a problem with the compiler. Don’t be one of those people who sends me angry, profane emails about a problem that you caused yourself; that’s just embarrassing.