algebraicthunk.net/ blog/ entry/ Windows stupidities

As I've had to use Windows on a daily basis, I've found that I am no longer able to maintain my air of detached tolerance for the foibles of the system. In fact, I'm starting to get really infuriated with the utter boneheadedness of so many facets of it. Not so much things that are broken, as things that are done badly, and done so in the face of widespread examples of how to do it right.

Here are two simple examples that are emblematic of what Windows users have to suffer through.

(a) Mandatory file locks.

On Windows, every access to a file, by default, acquires a mandatory lock on it. Want to recompile the program you're working on? Sorry, you have to track down and kill all its running instances. Want to read that file on the network server? Sorry, you'll have to run around the office and ask all the people using it to close it.

Last week I got an email asking me to unlock a directory on our local fileserver so it could be renamed. It turned out that I was running an acroread process to view a PDF file...and that locked the directory from being renamed. Because, of course, the universe would implode if someone were to rename a file I had already loaded into memory. This is, however, better than how shared libraries are treated; trying to register a new version of a shared library with the system (the Windows version of ldconfig) will silently fail if programs have the old version mapped into memory. WTF? No, really, WTF?

Windows users get around this by having tools to find out which processes have a file open so they can terminate them with extreme prejudice. This is considered normal and acceptable behavior for a computer in the Windows universe. After all, in the real world two people can't use the same document at once, so why should they be able to do so on a computer?

(b) C# events.

They've been invented many times. Signals, events, hooks, whatever you want to call them, they're collections of function objects that are invoked when some particular condition occurs. It's a great way to make it easy to connect together objects that don't know about each other, they're simple enough that your average CS sophomore could implement them in a half hour, and the concept is so obvious (besides having dozens of examples of working and deployed implementations) that there's no way to screw it up, right?

Wrong.

Now, C# is generally a somewhat clunky language, but this is nothing to do with that (I am not, for instance, surprised that it's cumbersome to bind extra parameters to an event in a language that has little support for higher-order programming anyway). No, this is one of those utter idiocies that just make you scratch your head and go what the *@&# were they on when they did that? You see, when you call an event with no attached listeners, C# throws an exception. Just, you know, as a friendly way of letting you know that you didn't connect to that event.

But wait! It gets better! In order to test whether the event has any connected delegates (the Microsoft term for a function object), you ... compare it to the null pointer. Yes, that's right. Every time you call an event, you have to do this:

if(Event != null)     Event();

...because, of course, an empty collection of events is clearly the same thing as a nonexistant object.

I really wish I could be a fly on the wall at the meeting where this was decided. My imagination supplies a scene along these lines:

Scene: A smoke-free office somewhere deep in the sterile labyrinth of the Microsoft campus Programmer 1: "...and we call this bold new innovation 'events'! It's a way for you to perform method calls without knowing which method you're calling. We've found that it's amazingly useful when doing UI programming. I'm sure that introducing this new idea to the world will be yet another chapter in the Microsoft story of advancing technology!" Programmer 2: "Have you checked the corner cases? What happens if there is no method available to call?" Programmer 1: "Oh, of course! In that case, the list of methods is null, so we throw a NullPointerException. We thought about adding an IsEmpty property, but who would want to look up properties on the null pointer? Besides, hardly anyone will ever want to create an event that might not get connected to." Programmer 2: "Uhhh, sure, that makes sense to me."

...!!!?!?!?!

Comment by Ben Hutchings at 6:37 PM:

I no longer have to use Windows on my desktop, but I still have to make Windows test machines do my bidding. This included whipping up a custom ssh server (thanks, Twisted!) and an implementation of pkill. fuser -k is next on my list of things I need.

The situation with file locking is a bit more complicated than you've stated. Every call to CreateFile must specify sharing flags, and I've tended to find that most programs seem to allow sharing. However, there are Windows APIs that can provide a filename given an open file handle, which means open files cannot be deleted. They can, however, be renamed.

You may find Larry Osterman's explanation of the sharing flags somewhat helpful.

If I remember correctly, each process's current directory is locked against deletion, which is probably the real reason why Acrobat Reader was holding on to a directory.