I love JavaScript, even with all of its flaws. I know a lot of people disagree, but I’ve always felt JavaScript has been a great language long before classes, fat arrows, or transpilers came along. Because JavaScript is so powerful and flexible, most of the code running on the web today, with just a few shims, can still be executed on an ES3 engine built in 1999. That’s amazing.
JavaScript gave me my first taste of functions as first-class objects long before other “enterprise” languages had “lambda-functions” (which usually weren’t nearly as versatile). Because of its dynamic nature, I didn’t need to worry about API differences between browsers like XHR/AJAX or the DOM. I also didn’t need to define piles of interfaces and facades or bootstrap an IoC container just to write some application code.
I love where we’re headed. ES6 — err, ES2015 — is implemented virtually everywhere. Wherever it isn’t, Babel is widely accepted as the platform on which to build modern JavaScript projects. Just yesterday, babel-core alone had over 309,920 downloads on npm in just that day alone. Even ES2016 and ES2017 are nearly implemented in all of the modern browsers, giving us exciting features like async/await.
The thing I am most thankful for with JavaScript is how it helped expose me and countless others in my field to functional programming concepts like partial application, higher-order functions, closures, and even the difference between treating data as mutable/immutable.
One of the things we’ve been doing as long as I can remember is chaining methods. What seasoned JavaScript developer hasn’t written several lines using jQuery’s powerful chaining functions? Or, before we learned to leave built-ins alone, prototype.js?
As I dipped my toes into the realm of functional programming outside of JavaScript, I found myself jealous of F# and Elixir’s pipeline operator. The way chains read so naturally from left to right, the way more complex programs could be expressed as simple, sequential steps that flow one into another was just awesome. lodash/fp is pretty great, but .pipe/.chain have nothing on the “foo |> bar” syntax.
I was super excited to see the es-pipeline-operator proposal, but discouraged to see the lack of momentum and support behind it. For a time I believed it to be the better of the two proposals between the bind operator and the pipeline operator, because it behaved more like other FP languages behaved and it avoided usage of “this”.
Once the :: operator was implemented in Babel and I had a chance to play with it, after I got over my initial prejudice against using “this” again, I found it extremely powerful.
Watch how easy — trivially easy — it is to implement monadic “map” without any wrappers using the bind operator:
…or provide something equivalent to the “huh-dot” or “elvis” operator in other languages to safely traverse properties…
Before async/await came along, promises and generators were all the rage, but node.js and many other APIs still use callbacks. One option is to require/import the API, like the “fs” package, and “promisify” it, using the “promisified” copies. The bind operator gives us a much simpler option:
Combining it with “await” would make it even sweeter.
Are tools that involve “this” so bad, in JavaScript? As much as many of us feel we didn’t really need classes, we have them now, and you can’t really argue against “this” and have classes at the same time. “this” likely has no place in pure functional programming land, but JavaScript is a multi-paradigm language, enabling it to be useful and expressive in innumerable contexts.
Even so, maybe we can use :: to get a little closer to the pipeline operator. For example, given a function that adds all of its arguments together and has no notion of “this”:
It’s also been proven to me through hard experience that even modifying the built-ins like “Object”, “Array” and “String” just with the shims on MDN isn’t always safe, as you may have to share code with others who disregard best practices and common sense — but the bind operator allows us to write fluent, performant code without worrying about these details. So long as under the hood it works the same as “.call()/.apply()”, meaning it isn’t quite the same thing as Function.prototype.bind, extra/intermediate functions need not even be created by the JS engine.
I know there’s a few other ideas on what the bind operator should do — maybe we can just get this one aspect of it, the part where it basically de-sugars to invoking “.call”/“.apply” with whatever is on the LHS of the expression as the first argument. There’s also some discussion about options for passing “this” in some explicit way — which I’d suggest isn’t necessary, as lodash-bound and trine seem to illustrate. Although the bind operator brings with it the baggage inherent with “this”, maybe if JavaScript ever gets an explicit “this” notation for function arguments, we can all be happy!
Now that I’ve had a taste of chaining my functions together without wrapping them or reading them backwards or modifying built-ins, I love it and I really don’t want to go back. I don’t think the bind operator is going anywhere, and I see it popping up in more and more places, but we’ve been waiting a long time for something like this to materialize and even though it’s only a “stage 0” proposal, it’s so compelling.
Please, let’s make this happen. Thank you.