Thursday, 16 September 2010

Double-take

There's an issue with Microsoft's JScript interpreter (the one used by IE, Windows Scripting Host, and others) that you see mentioned deep in discussions of other things. I thought it would be worth just briefly talking about on its own.

Update: The newer version of JScript used by IE9 and up doesn't have this bug anymore. Yay! Still in IE8 and earlier, though.
Basically, if you use a named function expression in your JavaScript code, JScript will process it twice, creating two separate function objects, at two separate times: First it treats it as though it were a function declaration (even though it isn't), and then it treats it as the expression it is. This is not a distinction without a difference, either, as we'll see below. (Amongst other things, it creates "symbol bleed," putting the function's name in the enclosing scope in clear violation of Section 13 of the specification, which says that it should only be defined within the function's own scope).

What do I mean by function declaration vs. function expression (named or otherwise)? Here's a function declaration:
function foo() {
}
Here's an anonymous function expression:
var foo = function() {
};
And here's a named function expression — this is the one JScript (IE) has an issue with:
var f1 = function foo() {
};
The easiest way to tell whether you have a declaration or an expression is to ask yourself: Are you using it as a right-hand value? E.g., are you assigning it to a variable/property or passing it into a function as an argument? If so, it's an expression. If it's standalone, it's a declaration. Here are some further examples of named function expressions:
bar(function foo(){});

var obj = {
nifty: function foo() {
}
};
So first off, how do we know JScript is creating two function objects? Here's the easiest way:
var f1 = function foo() {
alert(f1 === foo); // alerts "false" on IE, "true" on other browsers.
};
f1();
So, okay, but what do we care? Well, let's say you want to hook up an event handler and have it unhook itself later if some condition is met:

Prototype example:
$('foo').observe('click', function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
});
jQuery example:
$('#foo').click(function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
});
Perfectly reasonable, but won't work on IE. The handler will remain attached, because when you unhook a specific event handler, the function reference you give has to be the same as the reference you want to remove. On IE, the above, it isn't: fooClickHandler isn't the same function that we hooked up. The expression returned a different function.

So how do you work around it? Just make sure you're using declarations, like this:

Prototype example:
function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
}
$('foo').observe('click', fooClickHandler);
jQuery example:
function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
}
$('#foo').click(fooClickHandler);
If you don't want fooClickHandler to be a symbol in that scope, wrap it up in a scoping function, like so:

Prototype example:
(function() {
function fooClickHandler() {
if (/* ...some condition... */) {
this.stopObserving('click', fooClickHandler);
}
}
$('foo').observe('click', fooClickHandler);
})();
jQuery example:
(function() {
function fooClickHandler() {
if (/* ...some condition... */) {
$(this).unbind('click', fooClickHandler);
}
}
$('#foo').click(fooClickHandler);
})();
Alternately, you could just not use names (and use arguments.callee to unhook the handler), but there are lots of good reasons not to do that (arguments.callee is slow on most browsers, not allowed in ECMAScript's new "strict" mode, and besides, names are good).

So what's this "symbol bleed" issue I mentioned? Well, according to the specification, the scope of the function name in a function expression is confined to the function itself, not the encompassing scope. So:
var f1 = function foo() {
// `foo` is defined here
};
// but not here
Whereas, of course, if that were a function declaration, the foo symbol would (of course!) be defined in the scope in which the function is declared.

(You can see this coming, can't you?) Since one of the times IE processes the named function expression it treats it as a declaration, it incorrectly defines the symbol in the enclosing scope — much like we would do if we didn't use the scoping functions above — which is incorrect.

Happy coding!

Sunday, 12 September 2010

Boot, Ubuntu, boot! Good dog!

This isn't about writing software, but it's a snippet, so...

I have a fresh new desktop based on the Intel DH57JG board on which I've happily installed Ubuntu 10.04 LTS desktop. Aside from a video mode detection issue, things are great, but I had an odd symptom: Ubuntu could successfully shut down and power off, but it would crash if I asked it to reboot. Just an annoyance, but surprisingly...annoying.

So naturally I consulted a Major Search Engine(tm)(r), and while I found several threads related to this problem, I never found one where the original questioner actually said their had been solved. I did find one where someone chimed in with "When I had that problem, adding reboot=bios to the kernel options fixed it." So I tried that, but no go. I also found a thread where someone said "I've tried the reboot b, c, and h options but..." So I figured there had to be more options for this reboot thing than just "bios" or none.

Well, it took some digging and installing the linux source (which is nicely packaged, so not like that's hard), and my machine now happily reboots when I ask it to. Because the options for reboot are a bit hard to find, here they are (for the x86 architecture) as of the Linux kernel 2.6.32-24:

warmDon't set the cold reboot flag
coldSet the cold reboot flag
biosReboot by jumping through the BIOS (only for X86_32)
smpReboot by executing reset on BSP or other CPU (only for X86_32)
tripleForce a triple fault (init)
kbdUse the keyboard controller. cold reset (default)
acpiUse the RESET_REG in the FADT
efiUse efi reset_system runtime service
pciUse the so-called "PCI reset register", CF9
forceAvoid anything that could hang.
(If you're curious, the answer in my case was reboot=acpi. At least, that was the first one I tried that worked, so I stuck with that.)

If you need a more up-to-date list, or a list for a different architecture, here's how I got that:
  1. I installed the linux-source package, which dumps a bzip2'd source tarball in /usr/src

  2. Uncompressed and untarred the tarball

  3. Looked at the arch/[architecture]/kernel/reboot.c file. Since I'm on an x86 processor on the 2.6.32 kernel, the full path in my case was /usr/src/linux-source-2.6.32/arch/x86/kernel/reboot.c but of course YMMV.
(Lest you think I was terribly clever finding the options in the source, the first place I looked was in the kernel parameters documentation —/usr/share/doc/linux-doc/kernel-parameters.txt.gz — but all that said was to look in reboot.c. :-) )

I applied the change by editing /etc/default/grub, adding that to the GRUB_CMDLINE_LINUX_DEFAULT variable, running update-grub, and rebooting (er, that is, shutting down and then starting up — rebooting would have crashed, of course).

Hope this saves someone else some time.

(If the title of this post seems oddly familiar but you can't place it, here.)

Thursday, 9 September 2010

Modern Youth

My son has now unequivocally demanded his own proper computer.

My son is not yet three years old.

At this rate, by the time he's six he'll have a better StackOverflow rep than I have.

Sunday, 5 September 2010

Beyond Either/Or

So I was doing a massive file comparison operation (hundreds of thousands of files, >100 GB of data) today on one of my Windows boxes and so naturally fired up the excellent WinMerge, my favorite — by a wide margin — Windows-based visual diff/merge tool. And it did something that is so smart, I just had to mention it.

Usually when you ask software to do an operation on a set of files you identify by wildcard or what-have-you, the software does one of two things: It either goes off and finds all of the files first, and then starts processing them; or it just starts processing and discovers the files as it goes. The former is useful for progress bars, for an early indication that maybe you've messed up your filters, etc.; and the latter is useful for those "I don't care how many there are, just get on with it!" situations.

So what was the smart thing the developers of WinMerge did? They did both. One thread went off to discover files, and another thread got on with the business of doing the comparison for me. It was exactly what I didn't know I wanted.

Are there trade-offs to this approach? Probably. You'll be asking the devices you're reading from to do two things at the same time for a while (list files and read files), which could impact overall performance. Or not, it depends a lot on what the devices are — do they have thrashing issues, are you maxing out your channel to them or does your post-receipt processing take most of the time, etc., etc. In my case, I was dealing with HDDs which presumably did have to thrash a bit (or a lot) early on, but for me it was still a really useful user experience.

So the point is, as it frequently is, to remember ask whether "both and" is an option when looking at an either/or choice. (One of probably three questions you should automatically ask when faced with such a thing, the other two being "is 'neither' an option?" and "are there more options?")

Or maybe the point is just to say "nice one" to the WinMerge devs. Either way.

Happy coding. -- T.J. ;-)

Friday, 3 September 2010

Brilliant - A periodic table of elements

Josh Duck has done a Periodic Table of the Elements for HTML5. Brilliant (and pretty). In the 20 or so years of HTML, surely someone has thought of this concept before — but if so, I'm certainly not aware of it. Props to Josh!

Wednesday, 9 June 2010

What every programmer should know about sysadmin

Link-post today: Do you write software that someone is going to have to deploy to servers and administer? Then read this question on ServerFault and its answers, most especially this answer. Then read them again.

'Nuff said.

Friday, 19 March 2010

Small is...useful

Micro-post today:

I'm an active member of a couple of places where people post questions and (hopefully) get answers to them. Time and time again I see questions like "I'm doing X, but it isn't working. Why not?" followed by 35-200 lines of code, of which the eponymous "X" is 5-10 lines of code.

People. Seriously. It's like you've never heard the maxim of the Old French Republic: divide et impera (in English, loosely: divide and conquer). Or to put it in even geekier terms: Create a minimum failing test case. There are two very good reasons for doing this:

  1. I give it 90% or better odds that if you build a minimum failing test case, you'll figure out why "X" isn't working.
  2. If (1) above doesn't work out for you, well, then you have this lovely minimum failing test case you can post so people can help you out.
See? Vincere-vincere!