Like a lot of people, I'm drawn to the idea of functional programming, and I enjoy using the functional building blocks in JavaScript. What I struggle with is performance, and I bump into it all the time. The difference between overwriting an array with a for loop and using map() is roughly an order of magnitude. I use map() and other functional primitives whenever I can, with anything small and with any code that doesn't need to be fast - which is admittedly most code. But performance matters often enough that I can't adopt a single functional style even though I wish I could.
Will there be a time when going functional will be not just the fast way to write code, but the way to write fast code? Are there efforts to create high performance functional primitives that are easy to use and also outperform their imperative alternatives? I've used numpy, for example, and I wouldn't necessarily put it in the easy to use category. I'm hoping one day I can write straightforward functional code and have it not be so much slower than imperative code that I have to question which one I should use.
Holy crap! I just had to check this and you are completely correct. map() is 10x slower in Chromium than overwriting an array. Interestingly, writing my own map operation in JS (by creating a new array and mutating it) was only 20% slower than mutating the original array. So something is very, very, very wrong with Array.map() on Chromium...
Then I checked it on Firefox. My hand-rolled map function is 3 times slower than the mutating version and the map() version is 1 or 2 orders of magnitude faster than the mutating version (as you would expect it to be).
So there is something wrong with Chromium, I think... Caveat: First thing in the morning on boxing day, back of the envelope style hacking. Having someone else verify my results would be nice ;-) Otherwise take it with a grain of salt...
Edit: The built in profiler was giving me strange results on Firefox, so I used the Gecko Profiler extension and it gave me something more reasonable: map() is about 50% slower than mutating the array and my handrolled map is about 20% slower than mutating the array. So that's a bit more consistent with Chromium's results.
It's very trivial (this is the bulk of it -- not showing everything to spare people from jumping over a huge message):
var f = function f(num) {
return num + 5;
}
var immutable = function immutable(arr) {
return arr.map(f);
}
var mutating = function mutating(arr) {
var i = 0;
var l = arr.length;
for(; i < l; i++) {
arr[i] = f(arr[i]);
}
return arr;
}
In my actual code, arr is a array of ascending numbers from 1 to 10,000 (different sized array each set of calls). I rebuild it before each call to immutable and mutating. I then run each of those functions, one after another 10,000 times. The intent is to make sure that there are no strange optimisations with a constant array and to even out the impact of the GC by interleaving the calls.
Unfortunately I tried to go to the link that you provided, but it just timed out :-(
Ah... it showed up. Hard to say what's going on there. I can't see the source code of how the benchmark works. But I do notice that you aren't returning the values. It is entirely possible that the code is being optimised out. I recommend returning the array. I also added up the elements of the array and checked that each implementation added up to the same number, just to make sure that the operation was actually performed.
Interesting. I did add a return to that benchmark and it didn't seem to affect the results. I would think your test would be identical to mine in performance characteristics, I wonder if it's just the benchmarking methods leading to the difference. I might just go write my own benchmarking like yours since I don't really know what measurethat.net is doing.
It seems intuitively obvious that map would be less efficient, but who knows what V8 is doing to optimize under the hood.
Given that they are so close in your example, I was thinking that it's possible that both sides are being optimised out, but that since the map side is smaller, it runs faster (i.e. the optimisation is at run time and so it still has to interpret the code -- smaller code interprets faster).
I haven't had time to revisit this since, but I think it's important. It is also possible that the profiling support in Chromium and Firefox is broken and I would very much like to know that if it is true.
Disclaimer: CS-Student who is interested in FP-languages but is yet not really experienced in this topic. I am also a bit drunk.
i think the problem is that js is not really designed for this kind of usage. If you look at this from the point pf view of an compiler FP is way easier to modify and optimize to improve performance. There are many factors but i believe the most important factor of future FP-base optimising compiler is rich type-info that makes many optimisation techniques possible or easier (this is important) to implement. While it's kinda boring, just look at haskell what possible there with rewrite rules. In a way it's possible to write your own compiler optimisation for your library.
In JS it's way harder because JS is untyped and the type system is way, way more complicated. Many of the hatches you use to optimise your program make it harder for the compiler to optimize your program. And i know about JIT-compiler, they are really complex beasts and the only way to tackle a language like JS. Just look (again) at Haskell, i always wondered what a really, really god JIT-compiler would look like. I would think that all the optimisation that you get by just using some pragmas would be only "engineering" work and don't require some fundamental breakthroughs. Especially if you consider the huge amount of time that went into something like the JVM.
> i always wondered what a really, really god JIT-compiler would look like.
Take a look at LuaJIT, then.
Also, I feel like it's worth mentioning that Haskell, OCaml, and Standard ML all have high-quality compilers available that can generate some pretty performant code. You won't get C speed out of them (at least not with idiomatic code), but you can wind up with executables that beat Java or C# perhaps, and easily beat the likes of Python, Ruby, Perl, JavaScript, ....
Take a look at asm.js. It's a subset of JS that uses de facto type annotations to let the JIT compiler get tremendous performance gains compared to normal JS - benchmarks put it at something like 1/2 the speed of raw C.
The problem, of course, is that (among other complications) you need to generate it from something that's completely strictly typed in order to do that in the first place, so most asm.js-compatble code is actually just generated anyway based on C or a similar language.
Typescript doesn't go far enough yet for asm.js code. It would need much more fine-grained types, like specific kinds of numbers instead of a single 'number' type.
I believe lots of people used FP to write short and correct programs; then they profile and tweak the bits that needs it.
Also, are you using javascript native .map method ? IIRC libraries like lodash or ramda, through use of reducers, have vastly faster idiomatic FP performance. Mostly because they avoid successive array allocation.
I'm not even sure it's reducers or transducers. It's mostly a type of functions, not the Array.reduce method. These function don't operate directly, they're meant to be recomposed later by the library. You can [].map(f).map(g).filter(h) and the system will "merge" f, g and h as a one step function that iterate once over the original data and without multiple array allocation. That's my partial understanding, there might be other subtleties.
"So, is JavaScript a truly functional programming language? The short answer is no.
Without support for tail-call optimization, pattern matching, immutable data struc-
tures, and other fundamental elements of functional programming, JavaScript is not
what is traditionally considered a truly functional language."
Time again I'm always surprised by how people over look type systems when talking
about functional languages. Really, much of that list is not fundamental to FP, but
always giving me an Int when you promise one matters.
But by that metric, you could call assembly a functional programming language and not be incorrect either.
There's a core set of features that FP languages implement so that people can be productive, and rich and expressive types certainly seems a key component.
Author/editor of Beautiful JavaScript here. I'm very confused by this website. It appears somebody took one chapter (Functional JavaScript) and re-published it as a book.
If you want to purchase the complete book do it from the O'Reilly website or from Amazon. All proceeds go to EFF.
> As I’ve often said, and as others at Netscape can confirm, I was recruited to Netscape with the promise of “doing Scheme” in the browser. At least client engineering management including Tom Paquin, Michael Toy, and Rick Schell, along with some guy named Marc Andreessen, were convinced that Netscape should embed a programming language, in source form, in HTML. So it was hardly a case of me selling a “pointy-haired boss” — more the reverse.
> Whether that language should be Scheme was an open question, but Scheme was the bait I went for in joining Netscape. Previously, at SGI, Nick Thompson had turned me on to SICP.
«I’m not proud, but I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients. The Java influences, especially y2k Date bugs but also the primitive vs. object distinction (e.g., string vs. String), were unfortunate.»
I saw a talk by him this year and I don't know if I have it remembered right, but the gist was that he wasn't hired to do a Scheme, but to do a scripting language inspired by it.
Just to be clear the prototypal inheritance came from Scheme, but the funcational aspects of JavaScript came from Lisp. Scheme's influence on JavaScript was, at the time, indeed an open question. On the other hand they absolutely told Eich not to do anything that resembled Lisp. JavaScript was to be Java's little brother and it had to look like and mostly act like its big brother. Eich made it work like Lisp anyways thinking they wouldn't notice given the incredibly short development window and the fact that as long as there was an inheritance concept it would satisfy the "feel enough like Java bit".
Of course nobody noticed JavaScript had influences from Lisp. It was buggy when it initially rolled out and it took a couple of revisions before nested functions were supported. This is backed up by David Flanagan's book "JavaScript: The Definitive Guide", which doesn't mention nested functions and closures until its third edition in 1998, because JavaScript didn't have closures until then. Whether it was a missing feature or due to a defect is something you would have to ask Eich directly.
Prototypal inheritances comes from Self, not Scheme. Self was inspired by Smalltalk, with a similar environment, but decided to abandon classes in favor of prototypes.
Brendan recently wished John Carmack best of luck with landing lisp in VR with his use of Racket for Oculus. Pretty cool seeing great engineers cheer each other on with common goals. Also interesting to see John, someone steeped in and super productive in many C variants, invest heavily in a functional language.
I don't know when the multiple times were. The language was designed in the span of a week or two if I remember correctly. That's a damn good job for language development given the constraints.
Watch Dave C.'s talk on the history of programing as it shines more light on the situation.
My concern with all these "functional javascript" posts is that people might (understandably) leave with the false impression that this is what functional programming looks like in general. It's like if you tried to get someone into cars by having them drive a Hyundai i10.
Regardless of whether you think JavaScript qualifies as a "functional language" just because it supports higher-order functions, the fact of the matter is that JS doesn't support 99% of the modern tools that actually make functional programming useful and not just a parlor trick. JS is missing everything from ADTs (possibly the single best thing to come out of early functional languages) to a type system. There are a few bolt-on structural type systems available (like Typescript), but they still don't get you even close to the full power of modern functional languages.
Sure statically typed functional languages are enjoying a lot of success right now, but there are still plenty of LISPs in the playing field like Clojure that can't be discounted as parlor tricks. You might disagree with them philosophically, but it doesn't change the fact they're being used in production.
What bothers me more about JS as a functional language is the lack of tail call optimization. While it's in the ES6 spec, last I heard there was some question of whether it would actually be implemented for web browsers.
OK, so "Haskell > Scheme", or some such. Any specifics beyond "ADTs", which I assume means Abstract Data Types - interfaces/polymorphism.
If IDEs ever get good enough to do near complete type inference, including reading through partial function application, and perhaps an "extract/move function" refactoring that converts closures to parameters, most of the class/type bondage and discipline may look a bit like a waste in retrospect.
Having worked in both static and dynamic type systems since the 80s, I've developed a bit of a "cringe" mechanism at the repetitive code that usually comes out of "strongly" typed languages. "This time it's different", but it never seems to be :-(
> Any specifics beyond "ADTs", which I assume means Abstract Data Types
No, I meant algebraic data types, although interfaces/typeclasses are great as well.
> If IDEs ever get good enough to do near complete type inference, including reading through partial function application,
I don't use any IDEs, but Haskell does this. I imagine various Haskell plugins do as well.
> and perhaps an "extract/move function" refactoring that converts closures to parameters,
I'm not sure why you want this so much, but it does exist. I've done this exact thing with Idris's interactive UI.
> I've developed a bit of a "cringe" mechanism at the repetitive code that usually comes out of "strongly" typed languages.
If there is one phrase that I would use to describe Haskell, it's "zealously anti-repetitive". If the Haskell community sees you writing the same line of code twice, they'll swoop down and beat you over the head with a well-designed typeclass until you stop repeating yourself.
Thanks for the response. Alas, here in "fly-over country" (Sacramento), it's all Java and some Javascript (or .NET, if you've been naughty). There's scarcely any Scala, let alone Haskell work to get or see here.
So, my background tends to be that I'd much rather do JS than Java. The JetBrains IDE's actually do a pretty good job at analyzing JS, despite JS's assumed inferiority. One day Java the language/syntax will be dead, and I will recover from the trauma it has inflicted upon me the last 10 years or so :-)
Fortunately, BS-CS programs still taught other languages beside C -> C++ -> Java in the early 80s, so I at least got to learn some Common Lisp back then (among other things), though not Scheme. Consequently, I'd like to move on from 1960s tech (e.g. - Simula 67) to 70s tech (e.g. - Scheme). Never learned me a Haskell yet. I suppose I should since it's got interesting stuff like currying built into the language itself rather than duct-taped on the side.
Just exposing people to a few basic patterns from functional programming will 1) encourage them to learn a real functional programming and 2) help them write better code.
Learning Haskell or Clojure or something is a big task, especially if you're doing it just because you're curious what all this functional programming is about. Everyone understand JavaScript, so being exposed to functional programming there is not a big deal.
And I love writing JavaScript with a bit of a functional lean to it. I think it makes it much easier to reason about the code. Of course it's not purely functional, but it's still better than if I wrote it the way many people do.
Or, alternatively, they just say "Hmm, this functional programming stuff doesn't seem very interesting or useful at all. Totally overhyped. Well, back to working with Blub."
"Functional" JavaScript is better than regular JavaScript in the same way that bloodletting is better than homeopathy; not much. Perhaps you've fallen into the same trap I'm talking about; do you think you're reaping any significant benefit from functional programming when you apply these sorts of practices to your JavaScript code?
One way or another, we're stuck with JS, so we have to use it and hopefully use it in the best way possible. There are genuinely good aspects to it and if you know what you're doing, you can write in a way that's easy for others to read and understand. Including certain functional patterns is part of that, and avoiding stuff that JS is terrible at, like "this", is another.
Clojure(Script) is easy to learn. Especially if you compare it to Haskell.
The core of the language is quite simple but leaning standard libraries will take time.
This is a good place to start http://clojurescriptkoans.com
> Everyone understand JavaScript, so being exposed to functional programming there is not a big deal.
(GHC) Haskell and Clojure are pretty big languages, so it's not surprising that learning them requires a lot of effort, but are you seriously suggesting that learning JavaScript (all quirks included) is easier than learning Scheme or Standard ML (all quirks included)?
I've honestly tried to learn JavaScript (in depth, not just whipping something together by gluing libraries foo, bar, qux), but several parts of its semantics continue to baffle me. Like “this”.
I agree. Reading YDKJS book helped. The trick is to realise "this" is like another argument to the function.
It varies by context, and will be set to the created object if new is used, set to global otherwise. You can also use the call function I think to set to something specific.
Anyway none of it really makes any deep sense to me, just a load of arbitrary features and traps.
FP like Haskell have a deep structure based in theory and maths, so although harder to make sense of initially, one you get it you don't forget it.
JavaScript has a lot of really weird/bad aspects to it no doubt, but you kind of have to ignore those parts and keep it simple. I actively avoid using "this" and it makes it so much simpler. There are four cases when "this" won't be what you expect, and the only common one is when it's in a callback, so it's not a huge deal, but I think the language is great when you just avoid it and all its other shitty parts.
That's how I feel. It's an otherwise pretty good language saddled with a bunch of misfeatures that the pointy-haired management wanted. (starting with the name itself)
Ignoring this/prototype and just using literals and closures goes a long way in simplifying JS, even if it's not as "performant" (formerly, "fast") at firing off that REST call when the user clicks that button. I'm not in a situation to use something like Node on the server, so I'd rather save my development time than a few nanoseconds of the computer's. (managing load times on web clients seems to be 95% of the bottlenecks for what I'm doing lately)
I didn't make any value judgments. Note the absence of the words “good” and “bad” in my previous comment.
Back on the original topic. What I said is that JavaScript is complex, not that it's bad. It may well be the case that JavaScript's complexity is essential for solving the problems it tries to solve. But you can't deny that the complexity exists. And you can't just wish existing language features out of existence, because the meaning of your code is given by what others can do with it.
In short: JavaScript probably has some simple subset. But, then, so does C++, famously.
You can easily get runtime ADTs from libraries like tcomb and folktale. While you lose out on some tooling, you gain advantages such as ad-hoc types and boundary checking (I.e. Ajax responses), as well as metadata (in the case of tcomb) for things like automated form generation and validation.
Upvoted because I think this is so spot on. Technically any language that lets you pass functions and capture variables is functional, but you ain't going to learn the beauty of FP from JS.
i love that you can require modules in node.JS functions. Having functions that dont depend on outside variables makes programming so much faster and easier. Being able to name functions also makes the code easy to understand and debug.
Will there be a time when going functional will be not just the fast way to write code, but the way to write fast code? Are there efforts to create high performance functional primitives that are easy to use and also outperform their imperative alternatives? I've used numpy, for example, and I wouldn't necessarily put it in the easy to use category. I'm hoping one day I can write straightforward functional code and have it not be so much slower than imperative code that I have to question which one I should use.