Writing software, the wrong way

Tuesday, April 1, 2008

Dynamic Javascript

For the next release, I want to start cleaning up the code base. I've started with grouppolicy's browser.xul (which overlay's Firefox's browser.xul) because this is a file that confuses me quite a bit. I also found out why it's seemingly so confusing.

The problem is this: Say I have a function called multiply that lives in another file :
function multiply(a,b) {
...
}

Without changing multiply's function internals, how do I change the logic? You might consider making a multiply2(a,b) and copy and pasting code and substituting your own logic, but the catch is you can't change any of the functions that call multiply() either!

It's sorta the same dilemma that we have. There are functions in Firefox's browser.xul that we don't want to change, but we want to add bits of logic jammed into the middle that would, for example, prevent a user from ctrl+click a link to open it in a new tab when tabs are disabled via a policy.

Overlays offer one solution. You can declare your own multiply(a,b) function and it would overwrite the one in Firefox's. However, I don't like this approach because you have to copy and paste code. And when you do that, you're responsible for keeping it current.

Another solution to wrap around the function. Let's expand our multiply function :
function multiply(a, b) {
var rv = 0, i;
// If we go over 999, just give up silently because we're evil
if (b < 1000) {
for (i = 0; i < b; ++i) {
rv += a;
}
}
return rv;
}

And let's say you wanted to change 1000 to 500. One solution is to wrap the function. Something like :
var _multiply = multiply;
function multiply(a, b) {
if (b < 500) return _multiply(a,b);
return 0;
}

Now the real multiply doesn't get called unless the second factor is less than 500. This is the approach I'm using to solve my problem. However, there is sometimes duplicate code that you just can't get around.

A third option, which is quite innovative, is something I found someone doing on an addon. It uses eval(), which is risky but gets the job done in this situation.
eval(multiply.toString().replace("1000", "500"));
I'll leave that for you to figure out. But it works!

Yay, bedtime!

No comments: