Michael Burke

Always Tread Lightly

I came across a funny bug the other day when checking in some code for our big project. I had my changes all double-checked and was ready for an svn update. So I pulled down the latest revision and did one more sanity check. Surprise! Nothing worked any more. What had happened?

Obviously, since I hadn’t been monkeying with any of my stuff in the short time I did the update, the problem had to lie in another javascript file somewhere in the project. The problem is, there’s only two other javascript files in the project that I didn’t write; one we develop and prototype.js. Surely the problem isn’t prototype, right? I double-checked our file and it was the same as the last revision. Which leaves us at prototype.js? The massively popular and well-tested javascript library? The one which was just working before the last checkout?

Sure enough, further poking revealed prototype.js as the source of the exception. I was creating an Ajax.Request to chat with a little JSON producer and it wasn’t even getting to socket opening. Instead, it provided me with this fairly cryptic exception:

[Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXMLHttpRequest.setRequestHeader]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: http://192.168.0.81/Exhibit/templates/prototype.js :: anonymous :: line 1284" data: no]

What? I mean, XMLHttpRequest.setRequestHeader() is obviously getting a bad value, but what in the world could it be? So I plunged into prototype.js itself and did more looking. It didn’t take long to find the problem section:

for (var name in headers)
  this.transport.setRequestHeader(name, headers[name]);

What was the bad value? It was a function I had added to Object.prototype, which implements class-like inheritance. It was getting picked up in the hash-style loop, which didn’t exist in the earlier version of prototype.js we were using, and passed along to setRequestHeader like it was any old primitive member variable. Removing the function from Object.prototype, making it a global function, and rewriting all the inheritance calls fixed the problem.

I won’t get into the argument about whether it’s kosher to modify Object.prototype. I’m not a style or standards zealot. I understand the reasons why it’s dangerous to modify Object.prototype. I also understand the power it gives a developer. The only thing anyone should take away from the discussion is that managing compatibility expectations is a constant process. One should always be on their toes.

Friday, February 20th, 2009 at 10:02 pm

Interact

Trackback
Make a Comment
Digg This
Submit to Reddit
Submit to Del.icio.us

CommentsComment RSS Feed

John Navratil says:

Thanks for posting this! The (also popular) json.js script adds toJSONString() to the Object prototype. OUCH!

Leave a Comment


Read more about

Javascript and CSS
flash

Zen Cart Wizardry.

Browse by Topic.

Can't Find It?

Other Interests.

Find Me On.

Michael Burke
beau@filterswept.com