3 ms·
I personally much prefer functional programming, however it has some downsides. The biggest practical hindrances I have found are: 1. Performance due to thing
by benjaminjackman 9y ago
I personally much prefer functional programming, however it has some downsides.
The biggest practical hindrances I have found are:
1. Performance due to things like allocations due to immutability thrashing cache, or a language that allocates on calling into closures, or fails to inline them properly, can be significantly worse depending on the environment you are writing your code in.
2. It's less common therefore there is a higher chance other programmers are going to struggle with your code, or that libraries aren't going to be as well supported.
Take lodash/fp for example. Vanilla lodash has really good @types support in something like Typescript. lodash/fp it's an open ticket (last I checked). This type of stuff happens a lot there just isn't the same number of folks writing code in fp style so you don't have the same level of long tail support.
3. This is maybe a less common view but in an object oriented style with code-complete, usually discover-ability is better. Typically the IDE has a better context of what you could be doing when chain method calls with a . rather than having the whole world of methods at your disposal when going for a code complete. For example when writing "abc".r<TAB> compared to r<TAB> the IDE is going to have significantly narrowed down scope to suggest in (methods that are legal on string). This can be very useful and I suspect narrows the breadth of the space the programmer must conceptually keep in there head from token to token. It's big reason why things like extension methods, which really don't have to exist (they could easily just be static helper methods) are frequently a highly requested addition to a language.
4. Somewhat related, and there are ways around this, I prefer a threaded / piping style as opposed to composing methods together. e.g. `(1 + 1) / 2` or
`(->> 1, (+ 1), (/ 2))` as opposed to `(/ (+ 1 1) 2)` To me I feel the code reads better from left to right as opposed to inside-out. But that is possibly (probably?) a result of being an imperative programmer for so long before switching to functional programming. Also I feel like I am playing around with a lot more parens matching and jumping backwards for something like f(g(h(x))) as opposed to h(x).g().f(). Again this could be my imperative programming upbringing leaking through though.
- ufo 9y agoFor point #4, you can use a "backwards application" operator like F#'s |> x |> h |> g |> f |> is defined by (x |> f) = (f x). I often find myself defining it myself when it is not in the standard library of my FP language du jour.
- guelo 9y agoVery much agree with your point 3. It's really a namespace issue with classes providing a natural division of the namespace. Also OO best practices over time have encouraged more modularization and encapsulation with heavier use of restricted visibility. At least in my experience functional code tends to pollute the global namespace with a bunch of not so obvious functions.
- TheNoseReaper 9y agoIt depends on the language but you often have the option of grouping functions accepting a specific input type in a dedicated module, and using them qualified.
- yorwba 9y agoIt seems like your points 3 and 4 could be solved by using a Forth-like syntax. "abc" r<TAB> would only suggest functions that can operate with a string at the top of the stack. Threading code would be `1 1 + 2 /`. There are no parens to match in `h g f`. Of course it's even more obscure than functional programming (point 2) and if the semantics aren't changed, point 1 isn't solved either.
- maxxxxx 9y ago3 is the reason why I write a lot of functions as static functions of a class. That way you get a list of applicable functions with auto complete.