Default Parameters, Episode V

August 4, 2008

I keep a pretty close eye on the searches that bring people to this blog. A lot of you are searching for how to sort in JavaScript (I’ll have to go into more detail on sorting soon). And a whole mess of you want to know about missing and default parameters.

I’m going to take another shot at the default parameter problem. I gave a solution that adds just one line of code per function, but it requires you to pass all parameters in a single object. I’ll adapt that solution to better handle the normal way of passing JavaScript parameters.

Really quickly, let’s talk about JavaScript parameters.

  1. When you pass in fewer than the expected number of parameters, the missing ones come in as undefined.
  2. When you pass in more than the expected number of parameters, the excess ones can be slurped out of the arguments pseudo-array. This array-like variable has the length method, but is missing other array methods.
  3. A common way to implement default parameters is with a series of statements like this: a=a || 1; The problem with such a statement is that so many different values evaluate to false that it’s easy to make a mistake and prevent a valid number like 0 from coming through.
  4. A better way to implement default parameters is like this: if (a===undefined) a=1;
  5. Another common way is if (a==null) a=1; This works pretty well because null and undefined are loosely equal to each other, but other falsy values aren’t equal to either of them.

Let’s modify my defaultHandler from my previous post on the subject so that it works with arrays instead of objects.

    defaultHandler=function(defaults,params) {
        var i;
        for (i=0;i<defaults.length;i++) {
            if (params[i]!==undefined) {
                defaults[i]=params[i];
            }
        }
        return defaults;
    }

Choose Your Poison

You now have a couple choices on how to use it. After the default handler is called, the array params will hold all your parameters in order.

    function test(a,b,c) {
        var params=defaultHandler([1,"banana",3],arguments);

        console.log(params);
    }

If you really want to, you can stuff the values back into the original named parameters…

    function test(a,b,c) {
        var params=defaultHandler([1,"banana",3],arguments);
        a=params[0];
        b=params[1];
        c=params[2];

        console.log(a,b,c);
    }

It’s a shame there’s no way to automate that stuffing of the parameters back into the original variables, isn’t it?

Ah, but there is. In fact, the whole process can be cleaned up with a bit of metaprogramming and some introspection. But that’s for Episode VI.

Note: This is the second post on default parameters. I took a cue from George Lucas on its numbering to try to get some search hits from the Star Wars zealots.


JavaScript Functions are Weird, Too

August 2, 2008

Remember when I said that JavaScript arrays are weird because they are also objects? Aside from their numbered elements, they can have, in addition, hash elements (a key and a value).

Believe it or not, functions in JavaScript are just as weird. They also are objects. If you have a function named bar, it can have a property named foo.

Doesn’t seem very useful, does it? After all, functions can already have variables declared inside them.

The difference? These special function elements persist from one call of the function to the next. You can use them to replace global variables that might otherwise cause unsightly clutter.

For instance, if you want a function to keep track of how many times it’s been called, this does the trick:

function add(a,b) {
  if (add.called===undefined) {
    add.called=0;
  }
  add.called++;
  return a+b;
}

or, more tersely but confusingly,

function add(a,b) {
  add.called=add.called+1 || 1;
  return a+b;
}

You don’t have to call the function by its name when you’re in the function, you can use arguments.callee instead.

How about a real world example. [Warning: You probably won't get your money's worth unless you compare the before-and-after code. I suggest copying and pasting them into a diff program so you can see the changes highlighted. Or you could just print out this whole blog post and take it to the bathroom.]

Alert! Unresponsive Script!

Sometimes, you might have some code that takes so long to execute that the browser alerts the user that a script has become unresponsive. That tends to take a long time for new browsers (they assume you might be running a Rich Internet Application and that such messages may be worse than the trouble they’re trying to solve), but for old browsers (like my nemesis IE6), the time is short. Something like 3 seconds.

Yummy Morsels

To solve this problem we have to break up work into bite-sized pieces.

Here’s our before case, the brute force (slow) solution to finding prime numbers. Adapted from a C version here.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title><!-- Insert your title here --></title>
    <script type="text/javascript">
        function findPrimes(topCandidate) {
            var primes=[];

            candidate = 2;
            while (candidate <= topCandidate) {
                trialDivisor = 2;
                       prime = true;
                while (trialDivisor * trialDivisor <= candidate) {
                    if (candidate % trialDivisor === 0) {
                        prime = false;
                        break;
                    }
                    trialDivisor++;
                }
                if (prime) {
                    primes.push(candidate);
                }
                candidate++;
            }
            return primes.length;
        }
    </script>
</head>
<body>
    <!-- Insert your content here -->
    <form action="">
        <input type="button"
               onclick='alert(findPrimes(100000))'
               value="Find Primes" />
    </form>
</body>
</html>

Now here’s the version where we only let 1000 numbers be checked at once. After 1000 have been done, we fall out of the code, but before we go we trigger a setTimeout with a delay time of 0. That’s all we need to do to let the browser catch its breath.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title><!-- Insert your title here --></title>
<script type="text/javascript">
    function findPrimes2(topCandidate) {
        var persist=arguments.callee;
        var tries=0;
        if (persist.candidate===undefined) {
            persist.candidate=2;
            persist.primes=[];
            persist.topCandidate=topCandidate;
        }
        keepTrying = true;
        while (persist.candidate <= persist.topCandidate && keepTrying) {
            trialDivisor = 2;
            prime = true;
            while (trialDivisor * trialDivisor <= persist.candidate) {
                if (persist.candidate % trialDivisor === 0) {
                    prime = false;
                    break;
                }
                trialDivisor++;
            }
            if (prime) {
                persist.primes.push(persist.candidate);
            }
            persist.candidate++;
            tries++;
            if (tries>1000) {
                keepTrying=false;
            }
        }
        if (keepTrying) {
            persist.candidate=undefined;
            alert(persist.primes.length);
        } else {
            setTimeout(persist,0);
        }
    }
    </script>
</head>
<body>
    <!-- Insert your content here -->
    <form action="">
        <input type="button"
               onclick='findPrimes2(100000)'
               value="Find Primes" />
    </form>
</body>
</html>

Compare the two versions. In the second, I’ve short-circuited the loop so that it only checks 1000 numbers to see if they are prime. To keep comparisons easy, I’ve tried to make the least number of changes I could. In real-world cases, you start with the idea that you’re going to work in chunks, and your code ends up cleaner.

Some Are Sticky, Some Aren’t

We’ve made some of the variables persistent. These are the ones that have to be kept across invocations of the function. All other variables dry up and blow away.

Since arguments.callee is such a long name, I’ve set the variable persist to hold the current function name.

This is not a recursive function. We let the function finish. It’s set up to be called again with setTimeout. You don’t want to is wait around in busy loops, making the browser all gummy and unresponsive.

If you do have responsiveness problems, put a longer delay and check fewer candidates at a time. This will make the process take longer, of course. It’s a trade-off.

Any wait longer than a couple seconds is going to make the user wonder what’s going on. A progress bar is the best solution for long waits. For short waits, a throbberis OK.

Program flow is not obvious when using setTimeout to control flow. In larger programs when you’re using this technique, you may want some kind of handler that’s in charge of passing control from one section of the code to another, instead of hardcoded setTimeout chaining.


Falsies

July 27, 2008

We call values that loosely evaluate to false “falsy.” What does “loosely” mean in this context? There are two comparison operators to test equivalence in JavaScript (== and ===). The first is loose, and the second is strict.

The results of the loose form are sometimes surprising, as you’ll soon find out.

What sorts of things are falsy? Douglas Crockford lists these: 0, NaN, the empty string(” or “”), false, null, undefined. In essence, they are the zero or false or empty versions of JavaScript’s various types.

Tripped Up

The worst trouble I have with falsy values are when I’m comparing to a number and I forget that 0 might be one of the numbers I’m going to get. I did this recently in my sorting post in the final bit of code. I used == when I should have used ===. (Note: I’ve since fixed the code in that post.)

I’ve had this blog post in my mind for about a month. I’ve been waiting for a stroke of brilliance to come so I could make all this falsy stuff completely clear once and for all. The stroke of brilliance never came, so I’ve decided to make a table for you that tell what falsy values loosely and strictly equal other falsy values.

== / === false 0 NaN null undefined “” (empty string) ” ” (white space) [] {}
false yes/yes yes/no no/no no/no no/no yes/no yes/no yes/no no/no
0 yes/no yes/yes no/no no/no no/no yes/no yes/no yes/no no/no
NaN no/no no/no no/no no/no no/no no/no no/no no/no no/no
null no/no no/no no/no yes/yes yes/no no/no no/no no/no no/no
undefined no/no no/no no/no yes/no yes/yes no/no no/no no/no no/no
“” (empty string) yes/no yes/no no/no no/no no/no yes/yes no/no yes/no no/no
” ” (white space) yes/no yes/no no/no no/no no/no no/no yes/yes no/no no/no
[] yes/no yes/no no/no no/no no/no yes/no no/no no/no no/no
{} no/no no/no no/no no/no no/no no/no no/no no/no no/no

In the table above, you see the result of each value when compared loosely (with ==), then when compared strictly (with ===). The next table tries to convert each value logically by negating the negation of it.

value !!value
false false
0 false
NaN false
null false
undefined false
“” (empty string) false
” ” (white space) true
[] true
{} true

Eye-Popping Results

Most interesting observations from the tables? How about NaN, which doesn’t even loosely equal itself? The empty object {} is the same way. They are the ultimate Dr. No’s. Interestingly, the empty array loosely equals false, 0, and the empty string.

A string of white space loosely equals more than I thought it would.

0 and false are pretty damned close to each other.

According to the first chart, NaN, null, undefined, and {} are not falsy, because they don’t equal false in a loose comparison. In the second chart, ” ” (white space), [], and {} and not falsy.

So, now you know why it’s safer to use ===. If you find a good use for ==, make sure you’ve thought hard about things that might go wrong. I might even go so far as to say you should comment every usage of ==, because it’s bound to be misunderstood in many cases.

Can you tell falsies when you see them? I used to think I could, but now I’m not so sure.


Do While Once in a While

July 26, 2008

The other day, a programmer I follow on Twitter was pleased because he had found a good use for a do/while loop.

When a programmer gets excited by a loop construct, you know something is wrong. The truth is that do/while is underutilized, not just in JavaScript but in all C-based languages.

The rule of thumb is that you should use always use a do/while loop when the body of the loop must execute at least once. Use a while loop when the body of the loop may never execute.

Maybe it’s true that a while loop is indicated more often than a do/while loop, but I’ve often seen programmers do a little jury-rigging to patch up the while loop to do their bidding when a do/while would have meant less typing and have made more sense.

Why? Well, programmers get into habits. If you get to know while very well, you may be shy about using do/while.

But I think there’s some clumsiness inherent in do/while that also plays a part in its unpopularity. It’s a result of JavaScript getting its syntax genes from C rather than the Wirth family of languages. Pascal and the others (Modula-2 and Oberon) used repeat/until

    JavaScript
do {
  a = a + 1;
} while (a!==10);

    Pascal
repeat
  a := a + 1
until a = 10;

I think repeat/until is superior to do/while for these reasons:

  • In JavaScript, the reuse of the identifier “while” is awkward. When you see it, you tend to expect the loop body to come after it. See how it just sits there AFTER the close brace? Like a teenage boy avoiding a girl at a middle school dance.
  • do/while’s ending condition is the same as while’s starting condition. Pascal’s until condition is logically negated, which I think is more natural at the end of a loop. Do something over and over UNTIL something is true, rather than do something over and over WHILE something is true. REPEAT UNTIL i hits 5, rather than DO WHILE i is less than 5. A possible solution would be to allow do/until as well as do/while. This would allow for backward compatibility. Someone remind me I said that the next time I invent my own computer language.

In short, the do/while construct just doesn’t sit quite right in C, encouraging the overuse of the while loop, which sits just fine. In any case, repeat/until seems to get more use in Pascal than do/while gets in C.

Don’t forget do/while is there, waiting for you to be excited to use it. It’s the right choice when you must execute the body at least once.


Sort of Confusing

July 25, 2008

Some of the worst JavaScript code I have seen has to do with sorting data.

JavaScript has a flexible array sort method, but it takes a while to get the hang of using it. Programmers seem to do fine sorting a simple array, but if the data format is something just a bit less trivial, many JavaScript programmers throw their hands up in the air. You can almost see the frustration in the code (sometimes in the comments).

One common situation that many people seem stumped by is sorting an array of objects based on a given key.

Suppose we have this array of objects:

    arr[0]={r:100,g:100,b:250};
    arr[1]={r:50,g:127,b:255};
    arr[2]={r:255,g:255,b:100};

Now suppose you want to sort the array by any of r, g, or b, and that you want to support both ascending and descending sorts. How would you approach the problem?

Back To Basics

Remember that to sort an array, you just invoke the “sort” method that belongs to JavaScript’s array type.

    arr.sort();

That works for sorting an array of strings, but it doesn’t work for sorting an array of numbers. That’s why even the novice JavaScript programmer recognizes the code for sorting numeric values.

    function sortNumber(a,b) {
        return a - b;
    }

    arr.sort(sortNumber);

JavaScript lets us pass in a function that is used to judge whether a value is less than, equal, or greater than another value.

Having that hook into the guts of the sort method lets us solve just about any sorting problem. But how?

Here’s a solution for the {r,g,b} problem above, where I want to be able to sort on r, g, or b in either ascending or descending mode.

    function sortByKey(arr,key,direction) {
        function sortNumeric(a,b) {
            if (direction=="ASC") {
                return a[key]-b[key];
            } else {
                return b[key]-a[key];   
            }
        }       
        return arr.sort(sortNumeric);
    }

The outer function is a handy way to keep the key (what we’re sorting on) and direction (which way we’re sorting) around, since there is no simple way to pass that information into the sort method. Remember that the inner function has access to the outer function’s variables, and that includes the parameters that come in.

Oh, by the way, the code is easier to understand if you recall that obj.r is the same as obj["r"]. We can pass in a string to a function and use that string as a key to get a value. That way we get around the need to write a separate evaluation function for each key.

Call the function like this:

    sortByKey(arr,"r","DESC");

to sort the objects in descending r order, or

    sortByKey(arr,"g","ASC");

to sort the objects in ascending g order.

Real Life Intrudes

Sometimes the data is not nice. You may have blank (empty or missing) spots in your data. In Excel, whether you sort ascending or descending, cells that are empty always show up at the end of the list. I recently needed to match that functionality in an Adobe AIR utility program I was writing. Here’s the code (blank cells from Excel ended up as empty strings in my data).

    function sortByKey(arr,key,direction) {
        function sortNumeric(a,b) {
            var c=a[key],d=b[key];
            if (direction=="ASC") {
                return (c==="")-(d==="") || c-d;
            } else {
                return (c==="")-(d==="") || d-c;   
            }
        }       
        return arr.sort(sortNumeric);
     }

A bit longer, codewise. But exactly what I needed for my data.

Once you get the hang of using inner functions, JavaScript’s sort method makes much more sense. It’s easy to extend this idea to accomodate other kinds of data (like strings), or to support secondary sorts, where a second key can be used to break ties.


9007199254740992

July 15, 2008

After my discussion of JavaScript’s numeric limitations when working with integers, I was curious. There must be some integer that’s the biggest one that JavaScript can represent.

A brute force method (my favorite kind) would simply increment a variable and see when it stops going up. Add one. Add one. Add one. Stuck.

That number is so large, though, that even I didn’t have the patience to wait for the loop to end. So I broke the problem up into two pieces.

First I set a variable to 1. I keep doubling it until I find a number that is the same as that number plus one. That’s my high limit and half that number is valid.

Then I do a binary search inside that range. The code looks like this:

    a=1;
    b=2;
    //find one that fails
    while (a!=b) {
        old=a;
        a+=a;
        b=a+1;
    }
    //do binary search
    low=old;
    high=a;
    while (high-low>1) {
        mid=parseInt((low+high)/2,10);
        a=mid;
        b=a+1;
        if (a==b) {
            high=mid;
        } else {
            low=mid;
        }
    }
    console.log(high);

The answer is 9007199254740992. Something over 9 quadrillion. Makes more sense why it would be a limit when you look at the number in hexadecimal. That’s 0x020000000000000.

That’s right. JavaScript can tell the difference between 9007199254740991 and 9007199254740992, but it thinks that 9007199254740992 and 9007199254740993 are the same. That falls out from the IEEE-754 double-precision floating-point spec that JavaScript uses to represent all numbers.

Remember that next time you want to write a for loop that counts to 10 quadrillion–it’s an infinite loop. You’ll never get there.


JavaScript Numbers Can Bite

July 15, 2008

Sooner or later, JavaScript’s numbers will bite you. They bit me in a probability function, and I didn’t even see it coming.

Maybe you took a probability and statistics class and learned about combinations and permutations. You may remember that the formulas for those involve factorials. Let’s take a look at my combination routine.

    //---------------------------------------------------------
    // Function: combinations
    //   returns the combinations of k objects from a set of n objects
    combinations=function(n,k) {
        function factorial(a) {
            return a<2 ? 1 : a*factorial(a-1);
        }
        return Math.round(factorial(n)/(factorial(k)*factorial(n-k)));
    }

Kind of an interesting looking function, isn’t it? When you find the number of possible ways that you can put together a k objects from a set of n objects, you need to do three factorial functions. Since I didn’t need factorial anywhere else, I stuffed it inside the combinations function.

But what’s the Math.round doing there? Aren’t we dealing with whole numbers here? Yep. In most languages, we’d explicitly declare the variables for this function to be integers, but that’s just not an option in JavaScript–all numbers in JavaScript are floating point numbers.

Trouble Ahead

So where do we run into trouble? If n is 23 and k is 2, combinations returns 253.00000000000003.

Even more frustrating is this answer because it’s one we can come up with off the top of our heads: If n is 24 and k is 23, we get 23.999999999999996.

What’s happening? Our numbers are growing so large in factorial that they can no longer be represented exactly in JavaScript. The solution? In this case, I fix the result with Math.round().

Playing Computer

But we can do better if we play computer with even a small case. Let’s take n=5, k=2;

combinations=(5*4*3*2*1) / ((3*2*1) * (2*1));
//largest number calculated is 120

That could be changed to

combinations=(5*4) / (2*1);
//largest number calculated is 20

A huge change. Much better. Three floating point operations rather than nine. Less chance for mischief.

Factorial is a well known function, and the combination formula is easy to write in terms of factorial, but that ease of representation comes at a huge computational cost, and in the case of JavaScript, sometimes a cost of precision.

If we rewrite the function to take advantage of this insight, we’ll be able to support much larger parameters before we run into trouble.

The General Idea

The solution to most of these problems is to rearrange the math so intermediate results don’t get as big.

This was a nasty problem to catch, because many results were calculated correctly. But it didn’t take long to come up with a couple solutions.


Welcome Mr. Future JavaScript Programmer

July 10, 2008

Your mission: You are a Web 4.0 programmer from the future. For some reason we cannot possibly comprehend, you have come back to 2008 to impregnate your grandmother.

While you’re here it’s crucial to your mission that you also write a Web 2.0 app. Difficulty? Working in our ancient dialect of JavaScript. Solution? Mascara.

No, you don’t wear it, you use it.

Mascara is a program that translates tomorrow’s JavaScript into today’s JavaScript.

It’s been mentioned in some of the big JS venues like here and here, but I’ve been watching since and the author is really knocking the cover off the ball with new releases. I want to make sure he gets the attention he deserves.

Here’s the site:

http://ecmascript4.com/

And here’s the blog where you can read his changelist:

http://blog.ecmascript4.com/

What’s This All About?

JavaScript moves slowly. Programmers are hesitant to use new features of the language until it shows up in all major browsers. You can’t just decide one day to move to the latest version. The version of JavaScript you have available depends on the browser that your client has installed.

Now, if you’re working on an Intranet, or on a Point-of-Sales system, you can mandate the browser. But for applications written for the web, you have to wait, and wait, and wait. Even after all that waiting, some people still haven’t managed to upgrade from IE6 yet. So you roll your eyes and wait some more.

One solution is to check to see if some language features are missing and provide them yourself (there are JavaScript libraries designed to help you out). That works fine when methods are missing, but it doesn’t work for new syntax.

What Mascara does it take future JavaScript (ECMAScript 4) and translate it into current JavaScript. It also does compile-time error checking.

Way to go We can all be future JavaScript programmers now.


You Could Lose Your Mind

July 8, 2008

What happens if you initialize an object with the same key (name) twice? I tried it in FireFox, Internet Explorer, Safari, and Opera.

In all cases, the last assignment (the rightmost one) is the winner.

var obj={a:1,b:2,a:3,b:4};

You end up with an object like this:

{a:3,b:4}

I’m not sure that’s mandated by the language spec. It might depend on the implementation. Anyone know?


Missing and Default Parameters in JavaScript

July 7, 2008

Passing parameters to JavaScript functions seems simple enough. Since the language is weakly-typed, all the parameters in the call are simply comma-separated.

And in the definition of the function it can get no more complicated than that–a comma-separated list of parameters.

Not much room for flexibility, is there?

But let’s take a closer look. Suppose you don’t pass all the parameters that a function is expecting. What happens?

If you shortchange a function, all the parameters you failed to supply are undefined.

What happens if you give more parameters than the function expects? They are ignored, but you can find they are still accessible in an array-like list called arguments. (No, it’s not an array. While it does have a length, it’s missing the methods that come with arrays.)

Now What?

So we’ve revealed a bit of flexibility–JavaScript won’t come to a screaming halt if you supply more or less parameters than a function expects. It’s more flexible in handling parameters than we might have suspected.

Some languages allow you to specify default parameters. Can JavaScript do that? Well, it’s not in the spec, but JavaScript programmers commonly provide default parameters using JavaScript’s || operator.

a = a || 1;

If a is undefined, a will be assigned 1. A will also be assigned 1 if a is 0. That’s not always what you want, so sometimes a condition is best:

if (a===undefined) {
  a=1;
}

Let’s try one. We’ll make a function that takes three parameters.

  • a will have the default value of 1
  • b will have the default value of 2
  • c will have the default value of 3
function test(a,b,c) {
    a=a||1;
    b=b||2;
    c=c||3;
    console.log(a,b,c);
}

We can call it like this:

test(1,2,5);
test(undefined,3,undefined);
test();

And get output like this:

1,2,5
1,3,3
1,2,3

If you have a lot of parameters coming in, that can get messy fast. Is there a better way?

There Is a Better Way

More than a few programmers have taken a stab at providing a nice default parameter implementation, and JavaScript is flexible enough to provide many ways to do it.

Most of these solutions feel over-engineered to me, so I spent some time thinking about the problem and came up with my own solution. I wrote a function called defaultHandler. This is going to be easy! Take a look:

    defaultHandler=function(defaults,params) {
        var i;
        for (i in params) {
            defaults[i]=params[i];
        }
        return defaults;
    }

We start with the “defaults” object that was passed in. Obviously, this holds all the default values for the parameters we expect to get passed in. Then we spin through everything that was passed in as a parameter and add it to the defaults, overwriting values when we run into identical keys.

Simple. Too simple, perhaps. The trick must be in how we use it. Is that it? Well, here’s an example.

    function test(obj) {
        var params=defaultHandler({a:1,b:2,c:3},obj);
        console.log(params);
    }

Hmm. Not much going on there, either. I told you this was going to be easy!

Here, I call our test function:

    test({a:5,x:"tuna"});
    test({});
    test({b:10,y:5});

And get the following output:

Object a=5 b=2 c=3 x=tuna
Object a=1 b=2 c=3
Object a=1 b=10 c=3 y=5

That’s all there is to it. Instead of passing parameters, we always pass in one single object that holds all the parameters.

In effect, we’re ignoring JavaScript’s “almost an array, but not really” parameter-passing system, and using a full-blown object to do the parameter passing work. Since objects can hold anything (numbers, booleans, arrays, objects, functions, probably even regex descriptions), nothing has changed except the packaging and naming of parameters. And we’ve gained tons of flexibility.

Come to think of it, you don’t even really need the default handler. That’s just a nice way of pruning down the parameters which need to be passed.

Why Would I Do This?

Imagine you’ve written an operating system. It has a nice windowing user interface. You have function calls like “OpenWindow” that take some parameters. In a later version of the interface you want to start adding parameters to the function.

It can get messy. You want to keep backwards compatibility so old applications don’t break. So maybe you have a slew of new functions like “NewOpenWindow.” Then you come out with another revision and you want to add still more parameters.

When it gets silly enough, you look for another solution. The Amiga guys solved this problem with taglists. Taglists were much like an object–a list of names and corresponding values. You only supply the parameters you want to.

That was the first time I saw this sort of solution. They added an OpenWindowTags() function and that solved the problem forever. Unfortunately, in the case of the Amiga, “forever” didn’t last very long.

It’s a great solution for APIs of JavaScript libraries. You can add new stuff in the future without breaking any old calls to your library.

A good rule of thumb is to use JavaScript’s normal parameter conventions whenever the number of parameters are small and it’s inconceivable that they might change. Otherwise, pass in an object.