The functional language that’s right under your nose
Recently I’ve been getting an itch to learn a functional programming language. I’ve made a couple attempts on Lisp over the years, with mixed results; I can write fairly basic Common Lisp, and hack on Emacs a bit, but I’ve never advanced much beyond that. I’d been looking at some of the trendy, popular functional languages (well, popular among certain circles) like Haskell, OCaml and Erlang, when I remembered that I already knew a functional language. In fact, part of the reason why I was hired at my current job was to write in it. And, as I browsed through a discussion of functional languages on reddit, it was literally right under my nose.
Yup, I’m talking about JavaScript.
Digression: stupid things people say about languages
Programming languages tend to be a bit like religions: people get attached to them, develop unshakable faith in them and are all too willing to wish hellfire and damnation on heretics who won’t see the light. As a result, they tend to spew out misconceptions about other programming languages in much the same way that a Protestant fundamentalist goes around saying Catholics are idolaters.
For example, a lot of folks who aren’t card-carrying members of the Church of Python (blessed be Guido and all His works) like to go around saying that Python isn’t “really” an object-oriented programming language, because you have to use self
.
Now, this argument really doesn’t make any sense; when defining a method on a class, the first parameter to it is self
, and inside the method you reference attributes of the class instance you’re working with as self.this
and self.that
and so on and so forth. The reason behind this is simple: it explicitly establishes variable scope (think about it: take away the self
, and you get things like foo = 3
— is that the attribute foo
of the class instance, or is it a variable local to the method? Using self.foo = 3
for the former case and foo = 3
for the latter does away with the ambiguity). Plenty of other languages do this; for example, Java uses this
and Ruby uses @
. Nobody tries to argue that Java or Ruby aren’t “really” object-oriented because of that; Python goes a little further and requires you to explicitly list self
as an argument to the method, but Python people like being explicit. If being explicit about scoping means Python isn’t really object-oriented, then being explicit about the types of variables and function return values means Java doesn’t really have a type system.
A lot of people will also say horrible things about JavaScript, because despite being a really interesting language, lots of people don’t like JavaScript (well, to be perfectly honest, lots of people don’t like the available implementations of JavaScript and, to be really honest, lots of people particularly don’t like the available implementations of one API that’s used a lot in JavaScript). For example, I’ve seen people try to argue that JavaScript isn’t “really” object-oriented because you don’t define classes using a class
keyword. JavaScript uses prototype-based inheritance, rather than class-based inheritance, but it is still a thoroughly object-oriented language.
Anyway, the whole point of these examples is to show that lots of people say silly wrong things about programming languages all the time, and mostly it’s got more to do with some agenda they’re pushing than with anything remotely resembling reality.
One of the things people might tell you is that JavaScript isn’t a functional language. They’re right, but only for certain values of “functional”.
What makes functional programming?
If we want to be pedantic about it (and if you know me, you know I always want to be pedantic), there are a few things which characterize “pure” functional programming:
- Obviously, everything is accomplished by calling functions. There are no “standalone” lines of code — the program starts by calling a function, which calls a function, and so on. Depending on what the program does, it may eventually terminate, or it may simply continue running indefinitely. In any case, everything takes place inside a function body.
- There is no global state and, to be perfectly pure, there are no global variables. Values can be passed into functions, but those values come from other functions, either as return values or as arguments passed from one function to another. But there is no “global scope”; each function has only a local scope to work with (even closures; their scope is just a bit wider and more long-lived than everybody else’s).
- There are no “side effects”. This is a consequence of the lack of global scope or state; since a function can’t “see” much, if anything, beyond its local scope (again, closures are a weird case), there is no way for a function to modify anything that isn’t handed to it.
This kind of pure functional style has some definite advantages:
- It can be easier to debug, since you can just walk up the stack to see what was called and with what arguments; this makes it simpler to pinpoint where bad data came from.
- It can be easier to write unit tests for, since each function can be called on its own and requires only its argument set; there’s no need for fixtures or any other environment setup.
- It can be easier to refactor, since you can muck about with the internals of a given function and, so long as you don’t change its signature, be reasonably assured that you haven’t mysteriously broken something else.
- It makes multi-threaded programming a little bit easier, because you don’t have to worry about things in Thread A modifying bits of program state that Thread B needs to work with (notice that I say “a little bit easier” and qualify “state” to “program state” — if the program is, say, doing database access, it’s still possible that one thread could modify important data, it’s just that the data is external to the program).
But a lot of this is academic; there aren’t a whole lot of pure functional languages, and when people talk about doing “functional programming” in real-world situations they’re rarely talking about pure functional programming. Common Lisp, for example, isn’t a pure functional language, even though Lisp is the patriarch of the functional language family. And OCaml, which is one of the darlings of the trendy functional programming world these days, also isn’t purely functional.
General mish-mash languages
Plenty of languages also support “multi-paradigm” programming; Python and Ruby, for example, both allow you to bounce around between procedural programming, object-oriented programming and functional programming, using each style wherever it best suits what you need to do. Generally these languages offer a few important features:
- Functions are first-class objects and can be the return values of, or arguments to, other functions. Not having this feature in a language makes functional programming of any sort diffcult, if not impossible (Java and C# people: imagine a world where you could just get a real reference to a method instead of doing indirection with delegates).
- The language supports closures. This is a tricky topic to explain correctly, but the essence of closures is that you can, for example, have code which generates and returns a function, and which magically “closes” up certain values from the enclosing scope and keeps references to them for use by the returned function, even when they would normally go out of scope before the returned function is called.
- The language usually — but not always — provides the ability to define “anonymous” functions. These are functions which are not defined by name, but which can be conjured up “on the fly” whenever a function needs to be passed in somewhere.
JavaScript has all three of these features: it supports closures, functions are first-class objects and you can define anonymous functions. This means that, in addition to doing procedural or object-oriented programming, you can easily do functional JavaScript programming.
The case for functional JavaScript
And there are a lot of times where you need JavaScript to be functional, even if you’re not used to thinking of it in those terms. Consider this example snippet of code, which — if you were using the YUI toolkit — would set up an event listener for clicks on an HTML element with an id
of ‘myelem’:
YAHOO.util.Event.addListener( 'myelem', 'click', function(e){ alert("You clicked the 'myelem' element."); });
This is obviously an extremely simple example, but notice three things:
- This is a function call.
- The final argument is a function.
- Not only is it a function, it’s an anonymous function.
If you’ve ever done any serious JavaScript programming, you were probably slinging functions — both named and anonymous — around all the time. Especially when you’re setting up event listeners or specifying more general callbacks, it’s just the most natural way to do things, but I’ve noticed that very few people, even people who write JavaScript day in and day out, realize that what they’re doing is a form of functional programming.
And that four-letter word that’s on everybody’s lips these days — you know the one I’m talking about — certainly encourages a functional programming style. For example, when making a remote call with the Dojo toolkit, a couple of the arguments to dojo.io.bind
are functions, and a large number of useful examples use anonymous functions defined on the spot. YUI’s asyncRequest
expects an object as one of its arguments, and several of the attributes of that object are, well, functions. Prototype’s Ajax.Request
(damn, I had to say it; why’d they have to put “AJAX” in the name?) expects, among the other arguments to its constructor, an object, at least one of the attributes of which is a function.
And, of course, Prototype and JQuery are very heavily functional (JQuery, from what I’ve seen of it, much more so); very nearly everything you do with them is a direct function call, and lots of the functions you’re calling can take functions as arguments.
In other words, once you start looking for it, you’ll start seeing functional programming everywhere in JavaScript.
So?
You’re probably wondering if there’s a point to all of this, and I’m not sure there is. Based on what I’ve been seeing on a few noteworthy programming-oriented news sites, functional programming is enjoying a bit of a renaissance right now, and I know I’m not the only one with an itch to play around in a functional language. But that itch often takes the form of working with an entirely new language, requiring you to spend time not only learning the concepts, syntax and standard library, but also getting a development environment set up for it: an IDE, any compilers, interpreters or runtime environments for the language, standard libraries… just getting the tools you need to play with the language can be a major time sink.
But JavaScript doesn’t have that problem. Text editors which understand JavaScript are free and plentiful, and the standard library plus runtime is built in to your web browser. With certain browser extensions, you can even get a REPL-style playground. And, best of all, JavaScript is an extremely easy language to learn, and odds are good you already have some experience with it. So if you’re thinking of dabbling in functional programming but aren’t sure you want to commit to learning a new language and setting up its associated environment, give some consideration to JavaScript. You might be pleasantly surprised at what you find right under your nose.