15 ms·
Functional Programming in JavaScript is Garbage
- igl 13y agoIterating with functions is terrible, I think I know that since I understood closures.
- briantakita 13y ago> Never forget that Javascript hates you. sigh Javascript just is. It only hates you because you hate it. Accept it for what it is and you & your code will be happier :-) Remember, abstraction loves you and doesn't need to be purely functional inside. It will still work. Breathe, Ahhhh.
- codygman 13y agoIt will still work, but you'll have to hammer on it/babysit/handhold the code into maturity more.
- platz 13y agoI'm not sure if it will solve the performance issues, but OP should check out PureScript.
- hetman 13y agoBasically criticism that could be applied to most practical languages out there. Of course, functional ideas are still very useful for writing clean code in those languages, provided the limitations are understood. I wish the article had been framed that way from the outset instead kind of admitting it only at the end. Instead we got an attention grabbing title that misleads the reader about the content/intent of the author.
- camus2 13y ago> Basically criticism that could be applied to most practical languages out there yet you're not forced to learn most of them. Now there is a solution from most issues the OP raises,but frankly Javascript is working against the developpers. That's why people say "embrace javascript", because it's a language that wont embrace the way you want to code. Javascript is a lucky mistake.And if not because politics we wouldnt be stuck with it. ES6 brings are few interesting things to the table though,and some scary ones like proxies,and god, people will abuse proxies and make code just "magic"...
- saraid216 13y agoIf you have not seen Gary Bernhardt's talk, you should: https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript https://www.destroyallsoftware.com/talks/the-birth-and-death...
- dclowd9901 13y agoNot that I'm a JS fanboy, but there are some flaws with the obvious bias presented here: 1) Strong Preference for Immutable Data: Javascript's object model isn't particularly confusing: If it's not a primitive, it's a reference. That's all there is to it. Knowing this, when architecting a functional framework in JS, one should know in the various instances they need to mutate data, or copy it. 2) Recursion & Tail Call Elimination: How would one solve this problem in any other language with a stack? Memory concerns don't just exist in the browser. 3) Functional Composition: It seems like OP's main concern here is garbage collection. There are ways to manage the garbage you generate here, and, frankly, engines like V8 do an exceedingly good job at cleaning up on their own. I don't blame people for not liking Javascript, and misdirected angst like this is at least good for keeping people on their toes about the many idiosyncracies of the language, but it won't go away just because you don't like it.
- cgag 13y ago1) Being able to describe it succinctly doesn't make it simple or easy. Mutability creates huge cognitive load. Every piece of mutability state adds exponentially more possible states for you to keep in mind. 2)http://en.wikipedia.org/wiki/Tail_call http://en.wikipedia.org/wiki/Tail_call ("Tail calls are significant because they can be implemented without adding a new stack frame to the call stack.") 3) I don't know enough about implementing partial in other languages to comment on if it's more garbage than should be necessary.
- deleted 13y ago[deleted]
- platz 13y agotranspilers might be able to assist taking a tail-recursive definition and unrolling it to a more low-level construct in the resulting JS.
- gargantuan 13y ago> 2) Recursion & Tail Call Elimination: How would one solve this problem in any other language with a stack? Memory concerns don't just exist in the browser. Be honest now, did you actually read the article ;-) because it answers that exact question. --- > Languages with Tail Call Elimination will recognize this situation and basically rewrite the function into a while loop. Since this is a low-level function, we should do the same, but sometimes it's hard to know when you're recurring dangerously. --- > but it won't go away just because you don't like it. I didn't like it and it go away. Out came Dart. I like Dart. All worked out well so far.
- Dewie 13y ago"choose the right tool for the job", "languages don't shoot people's feet, people do", """some appeal to popularity rather than technical merit""", "but it's multi-paradigm!", """some snark about academia, idealism, being out of touch with the real world""", """some languages-are-like-hammers analogy. or screwdrivers. or hammer-screwdriver hybrids.""", "it's only clunky because it's so pragmatic, worse is better" I thought I'd come prepared with some templates this time.
- briantakita 13y agoThe world would be a much better place if people didn't act like people and just do what I say...
- Dewie 13y agoThe world would be a better place if more people had substantial arguments to back up their opinions instead of their opinions just being distilled down into hollow platitudes
- deleted 13y ago[deleted]
- owenversteeg 13y agoI've only ran into an issue with JavaScript's garbage collection once in six years, and the problem was solved by carefully looking at my code and changing how I created images. Completely avoiding Javascript because of garbage collection is ridiculous given its other very useful things. I've written functional JS before and it's nowhere near as hard as this article pretends that it is.
- davexunit 13y agoThis pretty well describes my problems with JavaScript. We have first-class functions, but they are horribly crippled by the lack of tail-call optimization, immutable data structures (I don't want to mutate an array in order to implement map), and lack of arity checking. Alos, does anyone else get annoyed that operators aren't functions? I would love to write `_.reduce([1, 2, 3, 4], +, 0);` but instead I have to implement a sum function first. There's all sorts of little issues like this that make JavaScript a pain to work with.
- saraid216 13y ago> I don't want to mutate an array in order to implement map Er, what? > foo = [1, 2, 3] [1, 2, 3] > foo.map(function(i) { return i + 1; }) [2, 3, 4] > foo [1, 2, 3]
- davexunit 13y agoThat's _using_ map. Read an implementation of map to see what I mean.
- i_s 13y agoThat is using map, not implementing map. Implementing map: function map(f, ary) { var ret = []; for(var i = 0; i < ary.length; i+= 1) { ret.push(f(ary[i])); } return ret; } Though that is not a good example by the op, because that is what you do: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L2556-#L2557 https://github.com/clojure/clojure/blob/master/src/clj/cloju...
- deleted 13y ago[deleted]
- gotofritz 13y agoI would do it like this... function map(f, ary) { return [].map.call(ary, f); }
- rtpg 13y agothese arguments are bizarre in that either a) they're very easily avoidable or b) they exist in FP languages, just hidden - Immutable data arguments Nobody is stopping you from just working as if JS is immutable. - Recursive functions and the stack Tail call elimination would be nice. But for most common things, instead of writing the recursive call yourself, you'd use other common functions in the FP toolbox like map, reduce. You only need to find a good implementaiton of these base functions and 90% of your headaches are gone. But the stack is still an issue in other languages (See foldr debate in Scala). - Partial application and composition How do you think this is implemented in other FP languages? At one point you do have to store pointers to the functions you are composing to build the composed function , so you'll have at least one new object. >but if you are doing a lot of Point-free Programming, then your loops have the possibility of generating a ton of garbage. You shouldn't be doing something like for(..){ compose(f,g)(elt); } obviously, but this is just a specific case of "cache values". If you store the function beforehand, the amount of garbage created is linear to the size of your code, not of your data. (Never mind that you shouldn't be looping in FP). If you try hard enough and don't mind a more obscure syntax, you can actually reduce this function creation overhead too. var composeObj = Object.create(null); composeObj.prototype.invoke = function(x){ return this.g(this.f(x)); } compose = function(f,g){ var rV=Object.create(composeObj); rV.f = f; rV.g=g; return rV; } h = compose(function(elt){return 2*elt;},function(elt){return elt+3;}); h.invoke(10); If you're that crazy about FP garbage problems, this model will create exactly as much objects as any other compose function in any FP language (tag to indicate closure, pointers to composed functions).
- i_s 13y ago> Nobody is stopping you from just working as if JS is immutable. You cant just work "as if" things are immutable when they aren't. You have to be super careful about not mutating objects, for example copying an array with .slice() before messing with it. That is not ideal because 1) it is manual, and 2) copy on write is inefficient compared to the structure sharing that immutable data structures use. If you want the benefits of persistent data structures in Javascript, you have to use something like Mori. And that is ok, but not as nice as it is in functional languages, because you loose the specialized literal syntax to create the data structures and work with them. For example, to create a vector in mori you have to: var vec = mori.vector(1,2,3); And to map a function on it, you have to use Mori's special version of map: var result = mori.map(inc, mori.vector(1,2,3,4,5))
- chc 13y agoI feel like this gives a somewhat distorted impression of how FP in JavaScript compares to other languages. Many traditional functional programming languages are famous for creating lots of garbage and are not pervasively immutable either. Most of the progress in those areas is fairly recent. For example, Clojure's efficient immutable data structures are based on a book published three years after JavaScript was first released. Functional programming in a language without pervasive immutability does require you to do some thinking about how you want to approach state, but this is just as true in many traditional functional languages like Scheme. As for partial() and compose(), JavaScript already includes partial() in the form of Function.prototype.bind. And the compose() function shown there does not require the slice hack AFAIK, because it never does anything to arguments except take its length and access numeric indexes — but even if it did, I mean, that function has to do allocation in Scheme too.
- coolsunglasses 13y ago>Clojure's efficient immutable data structures are based on a book HAMTs aren't unique to Clojure. unordered-containers in Haskell has them, as well as Scala, Rubinius, and C++. There's a concurrent and lock-free version too. Haskell's efficient and immutable containers library is based on papers from 1993 and 1973. Persistent Search Trees have existed as a topic of research since at least 1986. So no, JS isn't excused here.
- chc 13y agoI didn't say anything was unique to Clojure. I used Clojure as an example because the OP did so. And, like, for any topic, you can usually point to some earlier research and say "Hey, look, there was this one paper so it's an old thing." But Haskell 98 wasn't even in existence when JavaScript came about. These were not mainstream ideas, even to the small degree they're mainstream now. The point is that JavaScript has similar limitations to many languages that were traditionally seen as supporting the functional style well around that time, such as most of the mainstream Lisps and OCaml. The ideas the OP is faulting it for not adopting were not well-explored despite having some old papers about them. (And from looking at history, I suspect trying to add those to the rush-job that was JavaScript would have resulted in eldritch horrors the human mind cannot fathom, so it was probably an OK choice not to get all experimental.)
- thinkpad20 13y agoHonestly I think JavaScript is about as good as any other mainstream dynamic language, save the Lisps, for FP. I'm currently writing a functional language and compiling to JavaScript, for the precise reason that it's a very straightforward translation. It's certainly much better at it than Python, although I consider Python vastly superior in almost every other respect. However, I think that FP in a dynamic language is very difficult because of the lack of typing. In Haskell you can write incredibly intricate and expressive single-liners that would be 10 lines in another language (if you could do them at all), and are only really feasible because of the typing system (as in, it would require almost a miracle to get them right without a type system backing you up). I suppose Lisp people manage to get away with it, but on the other hand Lisp isn't really functional the way the ML family of languages are. As far as the data structures not being there, well, keep in mind that JavaScript is based on imperative languages; hence its focus on arrays and hash tables (both of which are almost always implemented mutably). Also, mutability is baked into the DOM, and short of doing everything in a monad, that looks to be the way it's going to be, so again, it makes sense that JS was written as it was. When immutability is needed, use a library -- or just don't use JavaScript.
- kevingadd 13y agoAs long as you ignore the tremendous maintainability and performance hurdles preventing you from using FP javascript in production, yeah, it's 'about as good'. Other than the fact that it's incredibly poorly designed and has a shitty standard library. Blaming JavaScript's awful standard library on imperative languages is lazy. Almost every imperative language I've used has a standard library vastly superior to JS's, in breadth, depth and quality.
- thinkpad20 13y agoI didn't blame its standard library on imperative languages; I blamed its use of mutable data structures on that. I think the main reason it has a crappy minimal standard library is because for most of its lifetime it wasn't used for anything resembling "real programming." JS is a terrible language in many ways; don't get me wrong on that. However, I don't think it's any worse specifically at functional programming than any of the other mainstream dynamic languages (python, ruby, PHP, perl, etc), most or all of which are also founded on mutable data structures, lack of TCO, etc.
- gclaramunt 13y agoThe first argument is weak, arrays are THE mutable structure and no functional language uses it as it is. For the exact reasons of GC overhead, FP languages use persistent data structures meaning when you modify the data, what you get is (roughly) old data + delta , no need to deep copy anything
- taylodl 13y agoYou can trampoline without generating a temporary function. See http://taylodl.wordpress.com/2013/06/07/functional-javascript-tail-call-optimization-and-trampolines/ http://taylodl.wordpress.com/2013/06/07/functional-javascrip... for details.