13 ms·
Why I Prefer Functional Programming
- ts0000 7y agoAs someone strongly favoring a functional or even purely functional approach, I strongly dislike the flood of pro-functional-programming blog posts that attack the straw man of "imperative programming wrapped in classes". I don't want to believe that is what experts of the paradigm consider object-oriented programming. I would love to read an honest comparison of both, judging benefits and cost.
- marcosdumay 7y ago> I don't want to believe that is what experts of the paradigm consider object-oriented programming. Once you get to the scientific literature about the subject (where actual experts reside), it tends to be much more common to see the conclusions of "there isn't any formal difference between OOP and FP languages", or that in Haskell in particular "implements an strict superset of OOP". The problem is that FP and OOP are ill-defined concepts.
- AnimalMuppet 7y agoIn what sense is Haskell a "strict superset" of OOP?
- marcosdumay 7y agoIn the sense that you can recreate all the usual OOP syntax and behavior on Haskell. What people only do on practice for very limited extents, because it's not very useful to import those concepts to a language aimed at dealing with pure functions.
- rienbdj 7y agoFormal differences don't capture how awkward something can be to use. For applied programming this matters. Maybe I can do functional programming in Java, but if it's much more verbose than Haskell and the type checker occasionally falls over then it's not a good choice.
- lolc 7y agoWell said. I think a lot of people are drawn to Haskell because the abstractions are so well integrated. I remember reading the Prelude and muttering "wow so true" all the way. But then I got stuck when designing a first program. OOP to me is not imperative control flow but about managing responsibilities. What does this object know, what can I ask it to do, what does it need for the job? If I look at my program at the level of for-loops I'm lost in the brush. And granted, sometimes I do miss Haskell's expressiveness in the brush.
- p4bl0 7y agoI like functional programming too, but I'm not sure it is for the same reasons. Anyway, I think what the author describes as object oriented programming is actually imperative programming. In purely object oriented languages, such as Smalltalk, control flow can be encoded in objects too (for example Booleans can be an abstract class with two methods ifTrue and ifFalse that takes a callable object, and True and False can be subclasses that implements these methods by appropriately calling or not their arguments).
- fauigerzigerk 7y agoI think these sorts of examples dodge the real issue. Of course you can show a (perhaps needlessly) verbose procedural example of an algorithm that lends itself perfectly to FP and then demonstrate how FP is far more concise. But the real issue, in my view, is what happens when the algorithm is not ideally suited to FP, otherwise we're back to the cute inheritance hierarchies in OOP textbooks. Say we're dealing with something like the UK share matching rules [1], where you can't simply process your items in sequential order (because the cost of shares sold on a particular day may depend the cost of shares purchased on or after that day). The open question in my mind is whether pure functional languages scale well to problems of real life complexity, ugliness and the occasionally crucial optimization requirement. Does FP fall apart completely in those circumstances or does it just degrade to the point where procedural code was all along? I don't have an answer to that, but it may depend on how dogmatically the purity constraint is enforced. [1] https://www.accaglobal.com/uk/en/technical-activities/technical-resources-search/2014/december/share-matching-rules.html https://www.accaglobal.com/uk/en/technical-activities/techni...
- DubiousPusher 7y agoAgreed. My first thought was that you can do the exact same thing as the Haskell code in C++ using <algorithm> from the STL. The biggest advantage I find to functional languages is they force you to write code that's more testable and modular. I now actually write almost every OOP class to have all functionality in private static methods with the public interface methods mostly only doing the work of gathering the args for the private static methods.
- ignoramous 7y ago> The open question in my mind is whether pure functional languages scale well to problems of real life complexity. I came across this website [0] on news.yc way back when: It has a nice one-to-one mapping of GoF design patterns in C++/Java to Clojure. > The open question in my mind is whether pure functional languages scale well to problems of real life complexity OCaml [1] really shines in this aspect having used it in a project involving static code analysis. Facebook's ReasonML is based on it. The rust-lang compiler was once written in OCaml. And then there's amirmc's unikernel.org / mirage.io, as well. [0] https://mishadoff.com/blog/clojure-design-patterns/ https://mishadoff.com/blog/clojure-design-patterns/ [1] https://ocaml.org/learn https://ocaml.org/learn
- biznickman 7y agoI think this most effectively demonstrates why I like a lot of OOP: it can be verbose. This is example function is relatively illegible: alignCenter :: [String] -> [String] alignCenter xs = map (\x -> replicate (div (n - length x) 2) ' ' ++ x) xs where n = maximum (map length xs) One of the most verbose languages I've used, Objective C, has made this a best practice. Despite the brackets (which scare people off), it can be some of the easiest to read code.
- nnq 7y agoWhat is illegible about that?! It just says, in code: "replace each line of text with itself prefixed by a number of spaces equal with half of the difference between its length and the length of the longest line in the text". It's like the most obvious way to think about this particular problem! Now, how well this scales to different problems, and especially to problems where mutation is a natural way to think about things... that's a different problem and part of the reason I'm not that much in love with extremist functional programming. Mutation has its place and the monadic abstraction is something I dislike. But for simple examples like this pure FP rocks and is very readable and intuitive!
- marcosdumay 7y agoAs usual in FP code, the order of your words are completely different from the order things appear in the code. Also, most developers aren't used to concise function declarations (yeah, even with JS pushing them), what further adds to the problem. This is not something people with no experience on FP can read easily. Now, calling it illegible strongly implies that people with no FP experience are the metric one should code for, what is perfectly valid if you are at a company aiming to hire cheap coders, but not something to brag about.
- nnq 7y agoOrder of words is not that relevant, in English I can say instead of the above: "take each line of code [map ... xs] and replace it with [\x -> ...] a number of spaces equal to half the maximum line width [replicate (div (n - length x) 2) ' '] prepended to it [... + x]" All languages have passive voice and other tools so you can make the order of words be whatever you'd want for customizable emphasis while keeping meaning the same. Sure the order for arguments for `map` may not be the most intuitive, but that doesn't make things harder. See ReasonML for an example of functional programming with regular C-like syntax. Now, if you want to see hard to read functional code, look into code abusing point free style (I'm not even sure there is a fine way to use it at all...), plus mind bending types (usually to satisfy some monadic style abstractions), plus over-currying stuff all over the place. But the snippet above is only unreadable for people who stubbornly refuse to invest a couple hours of their time into learning a new notation for things! Heck, you can even translate it almost 1-to-1 to modern Javascript, or even add an extra function name and some more sensible variable names to make things more readable while keeping it functional: function alignCenter(lines) { let width = Math.max(...lines.map(ln => ln.length)); let getPadding = len => ' '.repeat(Math.max(0, (width - len) / 2)); return lines.map(ln => getPadding(ln.length) + ln); } ...the above is more like something I'd actually let pass code review in real life :)
- CJefferson 7y agoI don't see why "Object Orientated Programming" requires for loops, over map / streams (which Java has). Is there a definition of "OOP" which requires using for/while? This doesn't really sure any OOP at all. A better example would be to show a case where OOP would be useful, say having a base class and deriving it several times (iostreams for example). Show me how FP does somewhere where (traditionally) OOP is considered strong.
- anaphor 7y agoHaving for/while loops definitely isn't fundamental to OOP at all. Languages like Erlang and Racket capture the essence of OOP fairly well, yet you don't need to use loops to write programs in them.
- ChrisSD 7y agoIt depends what you mean by "OOP". Generally most mainstreams programming languages are mixed: that is they support more than one paradigm (e.g. procedural, class based OOP, functional, etc). Though I've noticed that programmers these days often equate OOP with classes. Therefore anything with classes is OOP whereas anything without isn't. This comes up a lot with languages, such as Rust, that are OOP but lack the class keyword.
- commandlinefan 7y ago> I don't see why "Object Orientated Programming" requires for loops Yeah, I think he (and most people who talk about FP vs. OOP) actually use OOP as a short-hand for "not FP": Scala is actually very object-oriented and very functional at the same time; they're not mutually exclusive.
- ezrast 7y agoAgreed. Ruby is a very fundamentally OO language, but its Enumerable interface is more comprehensive than many FP languages' equivalents (in addition to the standard map/reduce/select, it has methods for iterating over permutations of elements, n-sized slices, etc, all of which can be made lazy), and because it's an interface you can use it with custom data types easily. But FP enthusiasts often speak as if the ML and Lisp language families have a duopoly on higher-order functions. It's odd.
- tombert 7y agoI started programming (like a lot of people) after I bought one of those "Learn C++ FAST!" books (I don't remember the actual title). A large chunk of this book was about the object-oriented part of C++, and comparing it to the equivalent version in C, and acted that since the only two paradigms that exist are OOP and imperative, you should always use OOP. (NOTE: I'm paraphrasing, that was the tl;dr as I remember it from 18 years ago). Later, when I was 19 (around 2010), I was on an IRC board and someone was talking about how cool Haskell was, and when I asked him to explain why it was better than C++, he went into elaborate detail about how "C++ is total bullshit because you have to mix your types with your functions". He then went on elaborate detail (that went completely over my head at the time) about how Haskell's typechecker made C++'s look like "dogshit". Maybe I am too suggestible, but at that moment I agreed with him, and have kept that mentality ever since. I fundamentally do not like attaching methods to my structs/records/whatever, since I think that forces strong and unnecessary coupling. I do really hate the type systems of Java and C++ because I think they're restrictive and don't actually help. Obviously opinions vary; a lot of very smart people really like Java and C++, but I seriously cannot personally understand why. I feel like I get more done quicker with Clojure than I ever could with Java, and I have trouble comprehending anyone who says otherwise. I'm not trying to start any kind of flame war; if you like OOP we can still be friends, I'm not judging you as a person, I just disagree with your language choice :)
- partialrecall 7y agofyi, methods being attached to structs/whatever is a property of single dispatch object systems, but not multiple dispatch object systems. The coupling/attached relationship derives from single dispatch systems privileging the first argument of the method.
- MauranKilom 7y ago> I do really hate the type systems of Java and C++ because I think they're restrictive Can you give an example of how the C++ type system restricts you? Is it just lack of some inbuilt mechanisms/syntactic sugars or is there something that you can't actually model with it? > I think that forces strong and unnecessary coupling How do you model/maintain invariants of a set of data in FP? That's the part that I don't understand yet.
- throwaway5752 7y agoWhat I dislike about functional programming is that when objects are not supported or they are avoided I have seen poorly documented and complex hashes/collections data structures that end up reinventing the oop wheel (and the problem the wheel was solving in the first place). It feels like a false choice and you can have rich FP capabilities in a language that supports objects and relationships between objects.
- tombert 7y ago> omplex hashes/collections data structures that end up reinventing the oop wheel (and the problem the wheel was solving in the first place) I don't think I know what you mean here...Typically wheel-reinventing in FP languages happens because the stuff in the OOP/Imperative languages require a lot of mutation, which doesn't really jive in FP land for a whole plethora of reasons. > It feels like a false choice and you can have rich FP capabilities in a language that supports objects and relationships between objects. Sure, I'm partial to F# myself, but at some level I get frustrated when people try and mix paradigms too much. C++ has this problem of trying to be everything, and as a result it is very hard to read large C++ codebases. Scala isn't quite as bad, but it has similar problems.
- cerved 7y agoThen you should look into Scala
- foobar_ 7y agoI still don't get the point of immutability. Sure state change is a problem. How about a log like data structure that stores all modifications of the data? I'm sticking to procedural coding for the next 10 years and I will try my best to unwash young coders from poop.
- deleted 7y ago[deleted]
- roywiggins 7y agoThat seems like an implementation detail. If you have an append-only log, you can always rely on each entry to never change. That's a kind of immutability. If you hold on to a reference to the log at a particular time, it will never change out from under you.
- foobar_ 7y agoThere should be an alternative to both extremes - complete mutability and complete immutability.
- commandlinefan 7y ago> I still don't get the point of immutability If you're the sole developer, it's probably not a big deal. If you're working with a group of people, immutability is the only way to maintain your sanity.
- foobar_ 7y agoAs compared to POOP sure. How about as compared to Go? Go is a procedural language.
- recursive 7y agoYou can write mutation-style java tersely too... void alignCenter(String[] text) { int maxLength = 0; for (String line : text) maxLength = Math.max(maxLength, line.length()); for (int i = 0; i < text.length; ++i) { text[i] = " ".repeat((maxLength - text[i].length()) / 2) + text[i]; } } No lambdas to be found.
- AlexCoventry 7y agoI prefer functional programming because referentially transparent functions are easier to reason about and test. Brevity of control flow hasn't brought me much benefit.
- kbuchanan 7y agoCouldn't agree more! ... I just had to laugh to myself at how this, THIS is why functional programming is so... rarely adopted. Like, "referentially transparent functions"?! What happened to `website.run.now!`?!
- lemmsjid 7y agoReferential transparency is a handy thing to think about in OOP as well as functional programming. If you provide the same parameters to a function, will you always get the same result? If yes, and if the function is 'pure', e.g. does not result in some side effect like state manipulation, you could replace the function itself with the output of that function. If so, and the function is computationally expensive, you can memoize the function, which is a specific form of caching where you auto cache the results by the parameters passed to the function. This is a handy chain of reasoning in any language, and in a more dedicated functional language might be supported as a concept in the language itself. Like in OOP, you don't have to have that term memorized to actually use a functional language, just remember the pattern.
- tome 7y agowebsite.run.now is referentially transparent in Haskell (or rather, to mention the one I use, Happstack.Lite.serve: https://hackage.haskell.org/package/happstack-lite-7.3.6/docs/Happstack-Lite.html https://hackage.haskell.org/package/happstack-lite-7.3.6/doc...)
- carapace 7y agoYeah, in his Turing Award lecture introducing FP Backus made a big deal of the ability to reason about programs mathematically. I've been playing with a functional language Joy that combines (IMO) the best features of Forth and Lisp and one of the neat things about it is that you can derive functions from simple (almost geometric) syntactic manipulations as the whole language is just referentially transparent functions. ( http://joypy.osdn.io/notebooks/index.html http://joypy.osdn.io/notebooks/index.html )
- rb808 7y agoI like FP, but cautious as there aren't many big applications (open source or private) that are written that way. Am I wrong?
- myvoiceismypass 7y agoFP is pretty big in finance (not in trading platforms where speed reigns, though)
- klodolph 7y agoYou don’t need to go full FP to experience the benefits. You can just apply FP principles on a small scale to sections of your code, where appropriate. As for “many big applications”, it depends on what your threshold for “many” is. There are a number of firms that use e.g. Haskell, F#, or ML privately, e.g. Jane Street, Galois. For whatever reason, functional programming seems to be more popular in finance.
- munk-a 7y agoI may just be not familiar enough with them but I think FP tends to be a bit weaker when it comes to supporting code contracts which is a bit of a godsend when working on large projects - that said most also have very resilient type checking rules which can be used to the same end.
- blunte 7y agoTwo years ago, CircleCI posted about how they deploy their 100,000 lines of Clojure backend code and 30,000 lines of ClojureScript code to Google App Engine. Also, Walmart has been using Clojure "at scale" since before 2015. And based on a related tweet, the project at that time had 66 modules, 3000+ files, 560,000+ LOC (of Clojure). Last measure, Walmart was the largest US retailer at $374 billion annual revenue. I'd say their dependence on Clojure is a pretty good validation of the language's capability.
- haroldl 7y agoFunctional Programming is not just for Haskell; modern Java has lots of pretty decent options so I feel like their Java version of the code is a bit of a straw man. Here is how a more modern code style in Java 8 (which is years old now) might look. Notice that the logic for this problem is 7 lines of code, with one line being the closing brace. https://gist.github.com/haroldl/aee6a407a01131345fc4ecb1b9c9bec2 https://gist.github.com/haroldl/aee6a407a01131345fc4ecb1b9c9...
- deleted 7y ago[deleted]
- collyw 7y agoFunctional programming is all nice until you need to debug someone else's code. (Maybe it just because i have done a lot more of it with imperative style, but I am pretty sure that's the case for the majority of programmers).
- AllegedAlec 7y ago> Obviously, composition over inheritance strives a bit against one of the original key concepts of OOP - which is inheritance. I don't understand why people keep pushing this idea of OOP as requiring classes and inheritance, when it very much does not. Also, it's really easy to say that FP is better than OOP, or the other way around, when people keep comparing their favourite with a straw-manned version of the other.
- almostdeadguy 7y agoI assume you're referring to the definition of OOP coming from the Alan Kay quote: “OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things." This definition includes nearly every language with modules, polymorphism, and depending what counts as message passing might either dis-include statically typed languages, languages without a defined model of concurrency that disallows shared mutable state, or languages without message passing library support. If that's what canonically counts as OOP, there's no straw-manning going on here, the discussion is just a comparison against a pretty well-defined category of programming languages with different features that are often described as and understood to be object-oriented. Whenever people bring this up I often hear that Erlang is supposed to be the canonical object-oriented language, and if that's the case, I'm not sure how we could call this discussion straw-manning, because it's just talking about totally different languages.
- Traubenfuchs 7y agoDear functional programmer, please do not slam on languages you do not even know how to program in. To be honest, I have no idea what this code is even supposed to do and which idea of "centering" it satisfies. Whether this mess of Java or the mess of Haskell the blog writer created is more readable is up to you. C# has been functional forever and Java caught up a lot. int maxLength = Stream.of(text).map(String::length).max(Integer::compareTo).get(); IntStream.range(0, text.length).forEach(i -> text[i] = " ".repeat((maxLength - text[i].length()) / 2) + text[i]); (This becomes significantly more readable if you change the contract from passing an array of Strings to passing a list and returning a list. Since functional programmers are so in love with immutability: Java now provides immutable lists in the standard lib.)
- heisenbit 7y agoIs it just me or is iterative non functional code usually easier to debug? Or are the tools a lot more mature?