Thoughts from the office by Ed Ball
Thursday, March 31, 2005

When you start passing functions around, you often end up creating anonymous functions that call other functions with specific arguments.

For example, let’s suppose that we’re writing a DHTML calculator, and we have a function WriteDigit that writes the specified digit to the display. To set the onclick handlers of the calculator buttons, we could do something like this:

btnOne.onclick = function () { WriteDigit(1); };
btnTwo.onclick = function () { WriteDigit(2); };

That will work just fine, but there is another way. We can write a function that takes an integer as its argument and returns the anonymous function.

function BindWriteDigit(n)
{
  return function () { WriteDigit(n); };
}
btnOne.onclick = BindWriteDigit(1);
btnTwo.onclick = BindWriteDigit(2);

Why would we do such a thing? Well, one good reason is to avoid unwanted closures. Whenever you create an anonymous function, you’ve got to pay attention to the local variables that will be kept alive, particularly under Internet Explorer, as I alluded to in a previous post. In general, when you are creating anonymous functions that will outlive the function that is creating them, you should minimize the number of local variables in that surrounding function to prevent unwanted closures, accidental modification of local variables used by the anonymous function, and other surprises.

It would be a pain to write a separate binding function for every function that we want to bind; fortunately, we can write a function that takes a function as its first argument and returns an anonymous function that calls that function with its second argument.

function BindArgument(fn, arg)
{
  return function () { return fn(arg); };
}
btnOne.onclick = BindArgument(WriteDigit, 1);
btnTwo.onclick = BindArgument(WriteDigit, 2);

No need to stop with one argument, though; with a little more effort, we can write a function that will bind to any number of arguments by using the apply method.

function BindArguments(fn)
{
  var args = [];
  for (var n = 1; n < arguments.length; n++)
    args.push(arguments[n]);
  return function () { return fn.apply(this, args); };
}
btnOne.onclick = BindArguments(WriteDigit, 1);
btnTwo.onclick = BindArguments(WriteDigit, 2);

This technique comes in very handy, particularly in problems that are less contrived than this one. You can do a lot more than this with a sufficiently complex binding function; more on that in a future post.

Update: Fixed a bug in BindArguments. (Thanks, Bradley!)

3/31/2005 1:50:13 PM (Pacific Standard Time, UTC-08:00) | Comments [8] | Code | JavaScript#
Wednesday, March 30, 2005

As I mentioned before, for...in would be a convenient way to enumerate arrays, if it actually worked the way you’d expect it to. Fortunately, anonymous functions make it possible to write a ForEach method that’s almost as easy to use as a proper foreach.

function ForEach(array, fn)
{
  for (var n = 0; n < array.length; n++)
    fn(array[n]);
}

As you can see, ForEach calls the specified function for each element of the array. So if you’d like to calculate the sum of the items in an array:

function SumArray(array)
{
  var nSum = 0;
  ForEach(array, function (n) { nSum += n; });
  return nSum;
}

I hope you agree that this syntax is not only more compact than an explicit loop, but that it is also easier to understand. It is also less efficient, of course, but not significantly so, except in special cases where you would certainly measure to determine its impact; you could easily unravel it into a standard loop if necessary.

My preferred implementation of ForEach is slightly more complicated.

function ForEach(array, fn, objThis)
{
  objThis = objThis || this;
  var len = array.length;
  for (var n = 0; n < len; n++)
  {
    var r = fn.call(objThis, array[n], n);
    if (r !== undefined)
      return r;
  }
}

Let me explain:

  • Calculating the array length outside the loop can be slightly faster.
  • I pass the item index as the second argument to the called function, since that can often be useful. (The called function doesn’t need to declare it as an explicit argument if it doesn’t need it.)
  • If the called function returns anything but undefined, the loop is terminated. This allows us to simulate what would be a break statement in a normal for loop. The ForEach method returns the value returned by the called function.
  • If the called function returns undefined, the loop continues. (A function returns undefined if it gets to the end without hitting a return statement, if it hits a return statement without an expression, or if it hits a return undefined (naturally).) An explicit return statement without an expression thus simulates what would be a continue statement in a normal for loop.
  • Using the call method allows us to specify this for the called function, which can be useful when calling ForEach from an object method.
  • The objThis argument is optional, but I make sure that it is never undefined, because under Internet Explorer, the call method is slightly faster when the first argument is a valid object (passing undefined forces it to determine the “global” object itself).

For example, we can use ForEach to find an item in an array, returning the index of that item, or -1 if the item is not found.

function FindInArray(array, find)
{
  var index = ForEach(array,
    function (item, n)
    {
      if (item == find)
        return n;
    });
  return index === undefined ? -1 : index;
}

In many cases (but not all) I have found that using ForEach is easier to write and more natural than an explicit loop. YMMV.

Update: Explicitly described how to simulate a continue; thanks to Eli for his comment.

3/30/2005 8:53:48 AM (Pacific Standard Time, UTC-08:00) | Comments [3] | Code | JavaScript#
Tuesday, March 29, 2005

Emotional Design: Why We Love (Or Hate) Everyday Things, by Donald A. Norman, makes the case that products should be designed with human emotion in mind. That is, a product should not only work well and be as easy to use as possible; it should also evoke positive emotions in the people that use the product.

Taking this idea further, he argues that products – robots in particular – will ultimately need to evoke emotions themselves to maximize our satisfaction with them. His ideas are fascinating, often in the same way that science fiction is fascinating – it may be decades before advances in artificial intelligence can allow us to fully test them.

His opinion of most software is that it is too abstract – too “virtual.” If software is to appeal to our emotions, it needs to be more physical. We need to find ways to stimulate other senses than sight and mind – touch, hearing, smell… Knobs and levers are a good start – I’m not sure where he’d like to see it go from there. Page 83 suggests that there is little hope for existing software products: “Good behavioral design has to be a fundamental part of the design process from the very start; it cannot be adopted once the product has been completed.” To design a good product, you must observe potential users in order to understand their needs. From there, product designs need to be prototyped, tested, and improved iteratively.

In evaluating the effectiveness of product design, he considers three levels. Good visceral design has an appealing appearance. Good behavioral design produces products that work well and are fun to use. Good reflective design is how we feel about the design in the long-term – feelings of pride, good memories, etc.

This book was easy and fun to read; I recommend it to anyone that is interested in designing products that are not only useful, but emotionally appealing. It is not exactly full of practical advice, but it may get you thinking in the right direction.

3/29/2005 8:10:13 AM (Pacific Standard Time, UTC-08:00) | Comments [0] | Books#
Monday, March 28, 2005

Let’s say you want to sort an array of integers.

var array = [ 3, 14, 15, 9, 26 ];

You might think that you could just use the sort method of the Array. You’d be wrong.

array.sort(); // [ 14, 15, 26, 3, 9 ]

The sort method of an Array always sorts strings, which produces the unexpected result shown above. However, you can pass a function to the sort method.

function CompareIntegers(x, y) { return x - y; }
array.sort(CompareIntegers); // [ 3, 9, 14, 15, 26 ]

Now we’re talking. The CompareIntegers function returns a positive integer if x > y, a negative integer if x < y, and zero if x == y, which is what we needed for the sort method.

What if we wanted to sort the numbers in reverse order? Well, we could define a CompareIntegersDescending function, but it’s easier to use an anonymous function.

array.sort(function (x, y) { return y - x; }); // [ 26, 15, 14, 9, 3 ]

Very convenient. Here’s a function that can be used to find an item in an array.

function Find(array, fn)
{
  for (var n = 0; n < array.length; n++)
    if (fn(array[n]))
      return n;
  return -1;
}

The first argument is the array to search; the second argument is a function that returns true when the item has been found. We can use the Find function to find the index of the first item greater than 10:

function FindGreaterThanTen(array)
{
  return Find(array, function (x) { return x > 10; });
}

But what if you want to find the first item greater than an arbitrary number? Remarkably, this works fine:

function FindGreaterThan(array, n)
{
  return Find(array, function (x) { return x > n; });
}

This demonstrates the true power of anonymous functions. The definition of an anonymous function has access to any and every variable that was visible where the function was defined, including local variables. Furthermore, it retains access to those variables as long as the anonymous function lives, even after the calling function has returned! An anonymous function used in this way is called a “closure.”

Whenever you create an anonymous function that is stored in such a way that it will outlive the function call that created it (which is not the case in the example above) you need to keep in mind that every local variable of that function call will live as long as the anonymous function lives. (That’s right – every local variable, not just the variables that the anonymous function happens to use.) If any of the local variables are references to objects that aren’t needed by the anonymous function, this could prevent garbage collection from freeing otherwise unused memory; if the objects reference large amounts of memory, this can quickly become a serious performance problem. If you’re working with Internet Explorer, you should also be aware of a serious memory leak that occurs when reference cycles are created that involve DOM nodes; these cycles are easy to create inadvertently when using anonymous functions as event handlers.

Occasionally, you’ll want an anonymous function to support recursion, in which case you can use arguments.callee to reference the otherwise unnamed function.

var fnClearAll = function (obj)
  {
    for (var key in obj)
      arguments.callee(obj[key]);
    Clear(obj);
  };

Now that I’ve talked about anonymous functions, I can describe my favorite way to enumerate an array – see my next post for a description of the ForEach function.

3/28/2005 12:42:10 PM (Pacific Standard Time, UTC-08:00) | Comments [2] | Code | JavaScript#
Wednesday, March 23, 2005

I’ve had a difficult time getting through what could be considered the first book in this series, so I decided to read the .NET Framework Standard Library Annotated Reference (Volume 1: Base Class Library and Extended Numerics Library) instead. It’s written by Brad Abrams with various other contributors.

This book is mostly a reference book that covers a subset of the .NET Framework Standard Library. Considering the easy availability and detail of the MSDN documentation, you might not find this very useful as a reference. It does provide interesting summaries of the core namespaces, and it is nice to see all of the method signatures supported by a class in just a page or two, but I can’t see myself using it much for reference purposes.

Unsurprisingly, the selling point of the book is the annotations. I wish there had been more of them, but since the annotations are really the only interesting reading, it makes this book very easy to read through. Some highlights:

  • Don’t catch, throw, or even derive from ApplicationException.
  • ArgumentNullException and ArgumentOutOfRangeException take the parameter name as its first constructor argument, but their base class, ArgumentException, takes the parameter name as the second constructor argument (after the message).
  • Array.Copy can be very useful.
  • Prefer using SyncRoot to the Synchronized method.
  • Seal your custom attribute classes for better performance.
  • Expressions within a conditional method are not evaluated when the condition is not met. (So calls to methods within a Debug.Assert wouldn’t be called in Release mode.)
  • Delegates are immutable.
  • The static Equals method of the Object class deals with null.
  • Stream.Null makes a great bit bucket.
  • Streams work with bytes; Readers and Writers work with characters.
  • A ThreadAbortException is automatically rethrown if caught.

All in all, I really enjoyed the annotations, but considering how much of the book is uninformative reference material, I can’t say that you’ll find it worth the money.

Update: I should also mention that it comes with a CD that contains all of the samples from the book. More notable, however, is the 3,864-page PDF document that replicates the content of the print book, except that it includes documentation for each member of each class. Fascinating, to be sure, but certainly MSDN is more convenient.

3/23/2005 1:13:08 PM (Pacific Standard Time, UTC-08:00) | Comments [0] | Books#
Tuesday, March 22, 2005

I’ve been writing a lot about JavaScript lately, but C++ is my first and best love (in the realm of programming languages, anyway). I finally decided to hunker down and read through The C++ Programming Language (Special Third Edition), written by none other than Bjarne Stroustrup, creator of C++.

I have a decent amount of C++ experience, and have read many of the C++ books written since this one was published, so I didn’t expect to learn a whole lot. Still, it was fun to read – at least until I got to the chapter on streams – and the road to C++ mastery certainly requires it.

I tried to keep a list of interesting items as I read through:

8.2.8: A namespace should express a logically coherent set of features without imposing a significant notational burden. We need a lot more guidance in this area.

8.2.9.3: It is safer to define functions declared in a namespace outside of the corresponding namespace declaration.

// this works
namespace N { void F() {} }
// this is safer
namespace N { void F(); }
void N::F() {}

11.5: Individual member functions of other classes can be made friends.

friend Node * Node::GetNext();

12.4.1.1: Data should be kept in derived classes.

14.4.6.1: Exceptions from member initializers can be caught by enclosing the entire function body in a try block.

15.2.4: I’m finally starting to understand virtual base classes, but experimentation was the key when trying to figure out how they ensure that the shared base class constructor is only called once, particularly when non-default constructors are involved.

15.3.2: Base classes of a struct default to public, just like members.

17.1: Some relational operations can be created implicitly by using namespace std::rel_ops.

18.3.1: Input sequences look interesting.

18.4.2: I forget about many of the algorithms, like mismatch, inplace_merge, and stable_sort.

21+: I couldn’t bring myself to care enough about the Streams and Numerics chapters to read them carefully. I’ve just never had much use for them.

The rest of the book was somewhat interesting, but I enjoyed the first 20 chapters the most. You, too, should be sure to read this book if you’re on the road to C++ mastery.

3/22/2005 4:13:52 PM (Pacific Standard Time, UTC-08:00) | Comments [0] | Books#
Friday, March 18, 2005

Normally you access function arguments by name.

function WriteAll(a, b)
{
  Write(a);
  Write(b);
}

However, you can also access function arguments by index using the special arguments object. This technique is particularly useful when implementing a function that takes an arbitrary number of arguments.

function WriteAll()
{
  for (var n = 0; n < arguments.length; n++)
    Write(arguments[n]);
}

The arguments object has a length property and one integer property for each argument (starting with 0, of course), but its similarity to Array ends there – it has none of the other methods of an Array. It is easy enough to convert an arguments object to an array; I use SliceArguments:

function SliceArguments(args, nStart, nEnd)
{
  if (nStart === undefined)
    nStart = 0;
  if (nEnd === undefined)
    nEnd = args.length;
  var aResult = [];
  while (nStart < nEnd)
    aResult.push(args[nStart++]);
  return aResult;
}

The arguments object has another useful property; the callee property returns the Function object that is being executed. This is primarily useful for recursion in anonymous functions, since there’s no function name to use. (I’ll talk more about anonymous functions in a future post.)

The arguments object has one more property: caller. It returns the Function object that called the currently executing function. However, the caller property has limited use, and has been deprecated in the most recent versions of JavaScript.

One more item of interest – each Function object has a length property that indicates the number of named arguments of that function.

function Blorb(a, b, c) {}
// Blorb.length == 3
3/18/2005 12:58:31 PM (Pacific Standard Time, UTC-08:00) | Comments [1] | Code | JavaScript#
Tuesday, March 15, 2005

The nicest way to enumerate an array would be to use the for...in operator:

for (var obj in array)
  ...

Don’t do it. The biggest surprise to the uninitiated is that this enumerates the indexes into the array, not the elements of the array itself. You’ll also find that the enumerated indexes are strings rather than integers. Worst of all, you’ll find that the indexes aren’t enumerated in numerical order, but in arbitrary order. You’ve probably figured out by now that what you’re actually doing is enumerating the properties of the array object, which happen to include the properties whose names are non-negative integers, but would also include any other custom properties you had assigned to the array.

So, how to enumerate an array? Well, the best approach is the most obvious – walk through the indexes of the array with a simple for loop:

for (var n = 0; n < array.length; n++)
  DoSomething(array[n]);

For a small speed increase, pull the length out of the loop.

var len = array.length;
for (var n = 0; n < len; n++)
  DoSomething(array[n]);

However, my favorite way to enumerate an array is to call a ForEach function that does all this for me – more on that in a future post...

3/15/2005 9:05:23 AM (Pacific Standard Time, UTC-08:00) | Comments [0] | Code | JavaScript#
Friday, March 04, 2005

Arrays in JavaScript are really just Objects with properties whose names happen to be non-negative integers. They also have one very special property: length.

A new array has a length of zero.

var a = []; // a.length == 0

Whenever a property whose name happens to be a non-negative integer is set, the length is automatically set to one more than that integer (unless the length is already greater than that integer).

a[3] = true; // a.length == 4
a[9] = false; // a.length == 10
a[6] = false; // a.length == 10

JavaScript Arrays are “sparse” – no space is allocated for unused elements.

// a[2] === undefined, (2 in a) === false

Deleting an item in the array has no effect on the length.

delete a[9]; // a.length == 10

Explicitly enlarging the length of the array has no effect on the items in the array.

a.length = 12; // a[11] === undefined, (11 in a) === false

Explicitly reducing the length of the array automatically deletes any items in the array whose index is greater than or equal to the length.

a.length = 5; // a[6] === undefined, (6 in a) === false

You can use the length to add an item to an array (but prefer the push method).

a[a.length] = true; // a[5] === true, a.length == 6

Arrays support a number of useful methods that treat the object like a traditional array:

  • push, pop: Adds or removes items from the end of the array.
  • unshift, shift: Adds or removes items from the beginning of the array.
  • slice: Returns a range of array items as a new array.
  • splice: Inserts and/or removes items to/from the array.
  • concat: Combines one or more arrays to form a new, concatenated array.
  • join: Joins the string forms of the array items into one string.
  • sort: Sorts the items in the array.
  • reverse: Reverses the items in the array.

There’s no clone method, but you can clone an array by calling either slice or concat with no arguments.

3/4/2005 3:08:09 PM (Pacific Standard Time, UTC-08:00) | Comments [1] | Code | JavaScript#
Thursday, March 03, 2005

Since new object properties can be created at will, a plain old Object is quite useful in JavaScript.

One common use of an Object is as a simple data structure. For example, if you want to return multiple values from a function, you can return an object with multiple properties:

function SplitAt(str, n)
{
  var obj = new Object;
  obj.Before = str.substring(0, n);
  obj.After = str.substring(n + 1);
  return obj;
}

Or, using the abbreviated syntax:

function SplitAt(str, n)
{
  return { Before : str.substring(0, n), After : str.substring(n + 1) };
}

Another common use of an Object is as an associative array; specifically, a mapping from strings to objects.

var map = {};
map["George Washington"] = 1789;
map["John Adams"] = 1797;

Or:

var map = { "George Washington" : 1789, "John Adams" : 1797 };

To see if a string is represented by an associative array, you could simply check that it isn’t undefined (e.g., map["Ed Ball"] !== undefined), but a property can be explicitly set to undefined, so you should use the in statement (e.g., "Ed Ball" in map).

To remove a string from an associative array, use delete (e.g., delete map["Ed Ball"]).

To see all of the strings represented by an associative array, use for...in:

for (var str in map)
  write(str + " (" + map[str] + ")");

When using an Object as an associative array, make sure that your strings will never be the same as the name of a built-in property of Object, e.g., "toString" or "prototype". Why? Well, for example, unless it has been overwritten, map["toString"] evaluates to a Function object instead of undefined. Furthermore, "toString" in map will always return true, but for...in will never enumerate "toString", and delete map["toString"] will always fail.

Also keep in mind that future versions of JavaScript could add new built-in properties; for example, version 5.5 added "hasOwnProperty". When I want to make absolutely sure that I won’t have any conflicts with built-in properties, I prefix the string with a space character – no built-in property will ever start with a space, after all.

function Get(map, str) { return map[" " + str]; }
function Set(map, str, obj) { map[" " + str] = obj; }
function Has(map, str) { return (" " + str) in map; }
function Erase(map, str) { delete map[" " + str]; }
function Find(map, obj)
{
  for (var str in map)
    if (map[str] == obj)
      return str.substring(1); // remove space
}
3/3/2005 1:23:58 PM (Pacific Standard Time, UTC-08:00) | Comments [0] | Code | JavaScript#
Tuesday, March 01, 2005

JavaScript: The Definitive Guide, by David Flanagan, is an outstanding book about the JavaScript language. It has excellent documentation on both the “core” JavaScript language and “client-side” JavaScript as used by a web browser. Best of all, it doesn’t mix the two, which is particularly useful if you find yourself using JavaScript outside of a browser. It also gives the author a chance to dig deep into the core language, which is a far more powerful and expressive language than most people realize.

The second half of the book consists of three references – one for “core” JavaScript, one for “client-side” JavaScript, and one for the W3C DOM. The references aren’t nearly as useful as the first half of the book, since that sort of documentation is more widely available, but it could come in handy.

I have extensive experience using JavaScript both inside and outside of a browser, and have recently been studying the more “advanced” features. I was surprised by some of the details I had overlooked:

  • The switch statement uses identity (===), not equality (==), when looking for a matching case statement.
  • Each case of a switch statement can use any expression (not just numbers or strings).
  • The first expression of a for...in statement is evaluated for each item. (I don’t plan on taking advantage of that obscure feature.)
  • You can break or continue to a label.
  • FunctionName.length is the declared number of function arguments.
  • If a function used as a constructor returns an object, that object becomes the “new” object.
  • The push method of an Array can take multiple arguments.
  • In client-side JavaScript, “global” variables become properties of the global object, the window.
  • SCRIPT elements should use DEFER if they don’t call document.write.
  • The Internet Explorer event model has important differences from the standard event model.
  • The standard Error object simply takes a string in its constructor (in Internet Explorer, the Error constructor is documented as taking a number followed by the message; I have since discovered that the standard behavior is supported as well).
  • The substr method of String is deprecated in favor of substring or slice. (Unfortunately, I find substr far more natural than substring or slice.)
  • There are a lot of methods that only work in Internet Explorer (and this book only scratched the surface).

The book also talks some about “Object-Oriented JavaScript,” which I hope to talk more about in a future post.

If you are a JavaScript programmer but realize that you may only be scratching the surface of what is possible, or wonder why the language doesn’t always behave as you’d expect it to, I highly recommend that you read this book.

3/1/2005 1:36:27 PM (Pacific Standard Time, UTC-08:00) | Comments [0] | Books | JavaScript#
Search
Archive
Links
Categories
Administration
Blogroll