Thursday, May 15, 2008

JS Library Roundup

In Part III of the JavaScript Renaissance, we spent another long evening exploring Prototype, Script.aculo.us, and jQuery, and getting a feel for the scope and power of these popular DHTML/Ajax libraries. A good chunk of that time was spent hacking at the Firebug console and experimenting with live HTML documents for immediate feedback.

You can download the presentation here.

Thanks again to the Wheaton ex-Perl Mongers for coming out to learn a little more JavaScript. Come out and see the Perl Mongers reborn as the first arm of the new Polyglot Programmers group!

Addendum: Some of you at the presentation wanted to know to use Greasemonkey to import libraries into web pages after they've already been loaded. Here's the skinny:
  • Go to https://addons.mozilla.org/en-US/firefox/addon/748 and add the Greasemonkey Firefox extension
  • After you restart Firefox you should see the telltale monkey face icon down in the lower right corner of your browser window
  • Right click on the monkey face and select "New User Script..."
  • Give the new script an identifiable name like "load_prototype" or "load_jquery", a namespace (can be anything, I'm not entirely sure what it's even used for), and a list of URLs to include or exclude from running the script
  • Configure a text editor to edit Greasemonkey scripts
  • Finally, enter and save the script

Here's the script I used to load prototype and most of script.aculo.us. Obviously, you'll need to change the paths to point to the files where they're installed on your system. Paste this into your new Greasemonkey document below the comments:


window.addEventListener('load', function() {
var head = document.getElementsByTagName('head')[0];
var libs = [
'file:///Users/fred/Projects/js/prototype-1.6.0.2.js',
'file:///Users/fred/Projects/js/scriptaculous-js-1.8.1/src/effects.js',
'file:///Users/fred/Projects/js/scriptaculous-js-1.8.1/src/dragdrop.js',
'file:///Users/fred/Projects/js/scriptaculous-js-1.8.1/src/builder.js'
];
for (var i in libs) {
var script = document.createElement('script');
script.type = "text/javascript";
script.src = libs[i];
head.appendChild(script);
}
}, false);


That should be enough to get you started! Please hit me up if you have any questions.

Labels: ,

Sunday, February 17, 2008

Function Arity and JavaScript

A commenter on my last post asked about variable arity methods in JavaScript. Arity, for those unfamiliar with that term, simply refers to the number of parameters a function takes. In dynamic languages, however, arity is a more, well, dynamic concept, since a function can often be called with any number of parameters, or even with a collection to be taken as the argument list. So there are actually two different things going on, which I'll call invocation arity and declaration arity.

There's not much to invocation arity in JavaScript; you've probably seen it hundreds of times before. To determine the arity of invocation from within a method, just use the length property of the array-like arguments object:
SomeType.prototype.foo = function () {
if (arguments.length > 2) {
// do something requiring > 2 arguments
}
}

Declaration arity is similar: I can ask for the length property of the function itself. So for example, if I was passed a function into some higher-order operation, I might check the function's arity to determine how to invoke it:
function foreach(array, callback) {
for (var i = 0; i < array.length; ++i) {
if (callback.length === 1) {
// yield the element
callback(array[i]);
} else {
// yield the index and the element
callback(i, array[i]);
}
}
}

Beware declaration arity though: if your function is trying to be smart about its own arity by foregoing formal parameters and just using its arguments object, it will advertise its arity as zero:
function sum() {
var s = 0;
for (var i = 0; i < arguments.length; ++i) {
s += arguments[i];
}
return s;
}

print(sum.length); // prints 0

Labels:

Thursday, February 14, 2008

More Mongering

The Perl Mongers were at it again on Tuesday night, going above and beyond the call of duty, slogging through snow and slush to listen to more JavaScript tidbits. This time, we explored how to use JavaScript to interact with the browser window and HTML document, monitor and handle user events, and make remote HTTP calls. We finished up with some lively discussion questions about JavaScript libraries and frameworks and how they compete, relate, and stack on top of one another; so I'll try to go more into that question in the near future.

But for now, you can find the slides and samples of the presentation here.

Labels: ,

Eye Candy

As good fate would have it, I happened to stumble upon two really good Microsoft fonts yesterday -- Corbel and Consolas. Corbel is a clean proportional-width font, similar in some ways to Trebuchet, but a little more professional looking in my opinion. (The loopiness of Trebuchet is a little annoying, and the capital M always bothered me. Don't ask.) Consolas is a fixed-width font, almost entirely sans-serif like Lucida Console, except for a more Courier-looking lowercase g, i, and l. I've been satisfied with Lucida Console for programming, but it just falls a little bit short of great. But I think I've finally found a worthy successor.

By the way, don't even bother trying to run these without ClearType. You have been warned.

Unfortunately, these fonts aren't "free" (as in freedom), so I can't just post them for you to download. But they do come as a font pack for Visual Studio 2005 (if you have it installed) -- or for a lower-tech option, a little birdie told me that they come bundled with PowerPoint Viewer 2007.

Labels: , ,

Friday, February 1, 2008

Currying in Prototype

If you've spent much time in the functional or higher-order programming mindset, you've already gotten a feel for the expressive power that comes from the ability to compose new functions out of existing ones. In pure functional languages, one of the basic types of function composition operations is called "currying" (after Haskell Curry, an early pioneer in this particular space). When you curry a function, you essentially bind parameter values to it, and return a new function over the remaining parameters. Some languages have built-in support for currying as a fundamental operation (ML and Haskell, for example), but you can implement them in any language that supports closures and functions as first-class objects. The Prototype library, as of version 1.6, does this for JavaScript via the Function.prototype.curry method.

Here it is, in all its beautiful compactness (without the Object.extend confusion):
Function.prototype.curry = function() {
if (!arguments.length) return this;
var __method = this, args = $A(arguments);
return function() {
return __method.apply(
this, args.concat($A(arguments)));
}
};
We'll walk through line by line:
if (!arguments.length) return this;
If no arguments were bound, simply return the function as-is.
var __method = this, args = $A(arguments);
Store the original function in a closure as __method, and the arguments to be bound as args.
return function() { ... }
Nothing surprising here. We're going to return a new function.
return __method.apply(
this, args.concat($A(arguments)));
This is where the magic happens. The newly created function, when called, is going to return the result of calling the original function -- __method.apply(this, ...) -- with the original arguments -- args -- prepended to the invocation arguments.

An illustration is worth a thousand words:
function original(x, y, z) {
return x+y+z;
}

var bound_x = original.curry(10);
bound_x(20, 30) // ==> original(10, 20, 30)
// ==> 60

// sure, you can curry a curried function
var bound_x_y = bound_x.curry(20);
bound_x_y(30) // ==> bound_x(20, 30)
// ==> original(10, 20, 30)
// ==> 60
If you're still using Prototype 1.5, all is not lost. The Function.prototype.bind method happens to do argument currying as well as binding, so you can replace the curry calls with:
var bound_x = original.bind(this, 10);
var bound_x_y = bound_x.bind(this, 20);

Labels:

Friday, January 11, 2008

Testing Ajax calls in Prototype

If you're doing any kind of unit testing of Ajax behavior, you'll most likely come upon one minor annoyance. If you test your UI expectations in the context that fires the request, the callback won't have completed yet, and the elements you're setting or creating won't be set up. On the other hand, if you test your expectation in the context that receives the response, the test runner thread will have ended long ago, and any failures won't be caught and reported.

What you really want to do is disable asynchronous callback behavior for your test runs, but unfortunately there is no global configuration parameter for Prototype that controls that.

A little metaprogramming to the rescue.

Simply add the following to the top of your JSSpec test runner to override asynchronous behavior for your tests:

(function () {
var $$setOptions = Ajax.Base.prototype.setOptions;
Ajax.Base.prototype.setOptions = function (options) {
$$setOptions.call(this, options);
this.options.asynchronous = false;
};
})();


(s/setOptions/initialize/g if you're using the latest and greatest Prototype 1.6.)

Just fire the events that cause Ajax requests and test your expectations afterward.

One more thing:

If your Ajax response contains <script> elements, Prototype will kindly extract and execute them for you, provided that you pass evalScripts: true as one of your Ajax options. However, what you may not expect is that it executes them in a deferred callback using the browser's setTimeout call. I initially set out to patch Element.Methods.update, which handles the deferred evaluation behavior, in much the same way as I did setOptions, when it occurred to me that a more general solution would be more helpful for testing. Why not just patch setTimeout and setInterval so that they behave synchronously?

window.setTimeout = window.setInterval = function (f, timeout) {
typeof f === 'string'? eval(f): f();
}


(Again, do this in your test harness, not in your production code!)

Obviously, you're going to completely lose your desired timing behaviors, but if you're trying to test elaborate timing schemes in JSSpec or JSUnit, you're pretty much screwed anyway. But let me know if you find any neat tricks to accomplish that.

Labels: , ,

Wednesday, January 9, 2008

Advanced JavaScript: Not for the Faint of Heart

Thanks to the kind folks from Chicago Perl Mongers, who took two hours out of their busy lives last night to learn a little bit about the dark corners and esoterica of JavaScript.

Those who have only been exposed to procedural and class-based languages often find JavaScript's unique brand of functional programming rather unusual, if not downright confusing. Its lexical scoping and prototype chaining rules allow for some very powerful metaprogramming facilities; but the language is finicky, and the very features that provide so much power can also be badly abused and hacked. It seems fair to say that this has been the rule, rather than the exception, until the dawn of the Ajax revolution in 2005. Did you know that you can easily create arbitrarily deep inheritance hierarchies in JavaScript, even though the language has no concept of classes? Create higher-order functions that can bind or curry parameters to existing functions? Extend language and DOM data types with custom functionality?

The future seems a lot brighter now, thanks to the tireless work of folks like Douglas Crockford, Dean Edwards, and John Resig, and to cross-browser JavaScript libraries like Prototype, jQuery, and Base.

The JavaScript Renaissance, Part I: The Core Language
Presentation
Snippets

Labels: ,

Sunday, December 30, 2007

Christmas

LED binary clock for Christmas: $22.99.

Having a wife who can set it for me: Priceless.

Friday, December 21, 2007

JavaScript 1.7 steals shamelessly from Python

A colleague shared a Planet GNOME article with me this morning about using the Thread.js library to fake threads and write Erlang-style concurrency in JavaScript. After briefly investigating said library, I must reluctantly admit that I didn't realize how much really cool stuff there is in JavaScript 1.7 -- much of which has been imported from Python: generators, iterators, and array comprehensions.

I keep hearing people complaining that JavaScript is becoming too much like Python, and I never understood what they were talking about. Now I do. I just don't understand what they're complaining about.

Mozilla Developer Center - New in JavaScript 1.7

Labels: ,

Friday, October 26, 2007

Beautiful Code

I just finished reading Beautiful Code on the train this morning. After all the attention to writing algorithms and solving interesting programming problems in a beautiful way, what actually struck me most was the second-to-last chapter, "Code in Motion," by a couple of the developers of the Perforce source-code control system. The chapter is actually a discussion and elaboration of a whitepaper on the Perforce website called "Seven Pillars of Pretty Code." The beauty under discussion here has nothing to do with the elegance of algorithms, or domain models, or API's, though it has powerful indirect relationships to all these things. No, this paper is aimed purely at the stylistic beauty of source code, and the way it visually communicates its structure and intent. Or, to quote the opening sentence:

The essence of pretty code is that one can infer much about the code's structure from a glance, without completely reading it.

The paper doesn't need any additional explanation from me. I only want to point out a couple things that really crystallized for me while I read it.

First of all, I've always been fairly adamant about keeping code to 80 columns. This is not necessarily because I do a lot of coding in vi or anything, but for me personally, I tend to like to view multiple "panes" of code side-by-side while I'm working. (At least, that's the most persuasive reason I use against co-workers who use the monitor-width argument to defend their heinously long line-writing practices.) I've always intuited that narrow code is easier to mentally "parse" and comprehend, but I'd never before heard it expressed so beautifully:

... the left edge of the code holds the structure and the right side holds the detail, and big long lines mix zones of structure and detail, confusing the reader.

It was difficult not to jump up out of my seat on the train and shout, "Yes! That's it!" Of course, mindlessly making your code narrower in and of itself won't fix structure/detail problems; but long lines are almost guaranteed to confuse the two. I began to think about some of my stylistic quirks, and realized that almost without fail, they are driven by the structure/detail issue, even if the motivation has been a mostly subconscious one. For example: in general, anything in a comma-separated list always goes on its own line unless the entire list fits compactly and readably on one line. Breaking a list arbitrarily because you've hit the 80-column mark makes it impossible to see at a glance what your parameters are.

This discussion also segues nicely into the problem of indentation. Since I've been programming in Python for many years, this is an issue I've had a long time to think about. Most people coming to Python for the first time complain that the syntactically significant indentation is the one thing that stands in their way of really liking the language. It is frequently claimed by Python evangelists that code that uses syntactic indentation is actually easier to read than code that uses braces or do/end-type control statements to delineate blocks. I agree with this statement up to a point; but in a larger sense it's really beside the point. The more important point is that we should be going out of our way to eliminate it as much as possible:

Forcibly align the main flow of control down the left side, with one level of indentation for if/while/for/do/switch statements. Use break, continue, return, even 'goto' to coerce the code into left-side alignment. Rearrange conditionals so that the block with the quickest exit comes first, and then return (or break, or continue) so that the other leg can continue at the same indentation level.

Of course, it goes without saying, pull out conditional logic into smaller functions and methods wherever appropriate, with their own sensible indentation schemes.

What I love most about Python indentation isn't that short functions are easier to read; it's that long, deeply indented functions are impossible to read, and so you're virtually forced to refactor your code to make it comprehensible.