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.
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 = a.map(function (i) { return i+1; });
> a
[ 1, 2, 3 ]
> b
[ 2, 3, 4 ]
> a.map(function (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?
Continue reading about JavaScript's native map reduce and filter are wrong
Semantically similar articles hand-picked by GPT-4
- Are map, reduce, and filter turing complete?
- My brain can't handle OOP anymore
- Functional isn't always better
- The exciting future Javascript
- Do you really need immutable data?
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️