Last week I saw a tweet by @jhartikainen that made my heart skip a beat! He totally raped the definition of a one liner and made something that can be beautiful only to a giant functional programming nerd.

The gist that he posted looks like this:

//Is this abuse of array functions? :D
'20000001'.split('').reverse().join('').match(/\d{3}|\d+$/g).map(function(s){ return s.split('').reverse().join(''); }).reverse().join(' ');
//produces "20 000 001"

Now this might just look like so much brain sputtering madness to you, but it’s actually displaying something very awesome about one of my favourite programming languages — native implementations of map, reduce and so on.


Image by Dan Bock via Flickr

tl;dr –> JavaScript is starting to mix functional and objective programming in a bad bad way

I’m not exactly certain when JavaScript got native implementations of these as I’ve been using libraries like underscore.js for a while now to achieve this exact same thing. Actually wikipedia tells me this has been added in version 1.6 way back in November 2005. Six years ago and I didn’t know a thing about it.

That’s just sad. Why don’t more tutorials online talk about these features? How are people supposed to learn how awesome JavaScript is when most of the community works only with a very small subset of the language?

Some further searching tells me that the version of JavaScript most browsers currently support is 1.5 and since ECMAScript version 5, which is comparable to JavaScript 1.8, was only standardised in … December 2009, the browsers are quickly trying to pick up slack and get up to speed with that …

This makes me sad, I almost don’t feel like continuing this post … luckily though, Node.js is pretty good with the latest ECMAScript support so there’s still hope.

What’s wrong

Considering the horror show I just described, writing the rest of this post leaves a bad taste in my mouth, but I think the way JavaScript natively implements some features of functional programming is wrong.

The way map, reduce, filter and others are implemented in JavaScript is that they are methods of the Array class. And you call them as such:

[0,1,2].map(function (i) { return i+1; }); // adds 1 to every member
[0,1,2].reduce(function (a,b) { return a+b; }); // sums members
[0,1,2].filter(function (i) { return i >0; });  // removes members smaller than 1

As you can see all of these functions are a way to call a certain function on every member of the array. Nothing too special here, anyone who’s ever even sniffed at functional programming should understand how these three functions work.

But because JavaScript is a language that is both functional and objective in its design, this code suddenly becomes very ambiguous to read.

On one hand, you’re calling functions that are the epitome of functional programming. Obviously there are no side-effects and a copy of the array is returned, leaving the original intact. Immutable data structures and all that functional shebang.

But on the other hand, you’re calling these on an array, as the array’s methods. Obviously these functions belong to the Array and are therefore executed in place and the array’s state is changed.

Reading the syntax and knowing the basics of both objective and functional programming, both those opinions look like they should be true. Shouldn’t they?

Turns out, in this case, JavaScript returns a copy of the array and nothing at all happens to the original array. As we can demonstrate with the following quick test in the node.js console:

Merrick:~ Swizec$ node
> var a = [1,2,3];
> var b = (i) { return i+1; });
> a
[ 1, 2, 3 ]
> b
[ 2, 3, 4 ]
> (i) { return i+1; });
[ 2, 3, 4 ]
> a
[ 1, 2, 3 ]

So it would seem that what we have Β here is a case of functional programming, behaving as functional programming, neatly packaged into an objective syntax.

Which I guess wouldn’t actually be that bad were it consistent.

Other functions used in this exact same way usually change the array’s state. Both sort and reverse return the new array … but also change the original array’s ordering. Similarly every other function on the array ranging from shift andΒ pop to splice change the state of the array they are being called on and return … something (it depends on the particular function).

This means that reading JavaScript you are faced with the fact that functions called on objects are sometimes performing actions on the copy of the object and sometimes on the object.

That’s just confusing and bloody horrible from a language design standpoint don’t you think?

Why couldn’t they just create new global functions for these awesome functional programming concepts … I mean, the whole idea there is that functions get parameters and only parameters, functions in functional languages are supposed to be context independent. But here you have context dependent functional functions … it’s just a mess.

Is JavaScript fast becoming like PHP with its confused standard library? Or is it just going through a little identity crysis?

Enhanced by Zemanta

Learned something new? Want to improve your skills?

Join over 10,000 engineers just like you already improving their skills!

Here's how it works πŸ‘‡

Leave your email and I'll send you an Interactive Modern JavaScript Cheatsheet πŸ“–right away. After that you'll get thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over my 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

PS: You should also follow me on twitter πŸ‘‰ here.
It's where I go to shoot the shit about programming.