4 ms·
I usually put it like this. Instead of having 23 poorly-understood and often badly implemented design patterns, functional programming has two design patterns:
by stonemetal 14y ago
I usually put it like this. Instead of having 23 poorly-understood and often badly implemented design patterns, functional programming has two design patterns: Noun and Verb. Nouns are immutable data: from integers to record types to OCaml's unions to Scala's tree-based Map and Set. (Occasionally Nouns have to be mutable, which means they have attached Verbs. I'm glossing over that for now.)
Then I would have to ask how is that different than OO other than the straw man at the beginning. It has Nouns and Verbs, sure data is default mutable instead of immutable but immutable is certainly an option. OO typically calls their verbs methods instead of functions but referential transparency is a good thing on the OO side of the fence too. We tend to call map for_each, etc.
Frankly I am beginning to realize that FP vs OO is the biggest bike shed I have ever seen in the real world.
- Robin_Message 14y agohttp://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent The real differences are in solving the expression problem (verbs are easy to add in FP, nouns are easy to add in OO), and as you say, OO's default of mutability vs FP's aim at referential transparency.
- michaelochurch 14y agoThe problem with the mutability debate is that most examples show two programs, one mutable and one immutable, on the scale of about 20 lines of code. At the small scale, it's a toss-up which is better. Often the mutable solution's more intuitive for most programmers, and sometimes just flat-out superior: more clear, easier to understand. Mutable state isn't evil. It's necessary in the real world. It's just that stateful actions don't compose well, especially when you involve concurrency or Big Code problems. Good programmers learn that they need to manage (not eliminate) mutable state. That's what FP is about. So the aesthetic dominance that FP advocates hope to establish with their 20-line A/B depictions doesn't come through, because the truth is that the problems with mutable state very rarely show up (except in contrived, over-complex examples) at 20 LoC. At 20 LoC, the snippet you'll like better is going to be the one you're most familiar with. The real differences show up at 2000 LoC, which can't be put in a PowerPoint. Immutable programming is somewhat less prone (but not immune) to complexity creep. For example, you see 500-line for-loops in corporate software all the time. The conceptual integrity is gone because so many people (who never learned what the others were doing) have added tweaks to it. The difference between mutable and immutable programming is that making that sort of change to an immutable program also changes the API, unless it's purely a performance tweak (e.g. plus(2, 2) still returns 4, but does it faster). If you add logging to plus in a purely functional world, you change its signature from (Int, Int) => Int to something like (Int, Int) => (Int, String). As you might guess, that's a double-edged sword. Sometimes you want people to be able to add "purely stateful" (i.e. no API changes) effects without changing a signature... but very rarely. So I think the major upshot of immutable programming is that it makes it impossible to add many varieties of complexity that corporate engineers tend to add silently (in pursuit of a short-term hack) without changing an API and breaking the build. This slows down complexity creep, and that's a good thing. It's the reduction of that externalized-cost/complexity-creep dynamic that makes FP superior, in my opinion. A 60-line referentially transparent function really isn't less evil than a 60-line method of an object. They're both fucking incomprehensible, in most cases. You're just less likely to see the 60-liner in a mature FP codebase. Also, because functions compose better than stateful actions, it's usually a lot easier to break large functions up long before they get anywhere near 60 lines. (In my opinion, double-digits are "warning" territory and 25+ lines means it should almost always be split, at least into inner functions.)
- seanmcdirmid 14y agoWhen you have state...I mean real state, it sure is nice to encapsulate that state in an object rather than in what is basically an unencapsulated monad. OO supports state encapsulation, pure FP basically does not, that is a big deal. Immutable programming sort of side steps the issue, that state is needed at all, that an interactive program can somehow be stateless is ridiculous, even many batch programs require some form of state (even if it is unencapsulated in a monad). Your 60-line function decomposed into nice small parts using beautiful composable abstractions is an FP pipe dream. Yes, if the problem is well understood, someone has thought about it for a long time and has come up with some beautiful abstraction that works for a narrow set of related problems. Now, as soon as you venture outside of a well-understood/nice abstraction domain, your code is just as bad in FP, if you can figure out how to implement at all.
- se85 14y agoOh really? A pipedream you say? Oh ok then...
- seanmcdirmid 14y agoLet me reply your one liner with my own: nice elegant composable abstractions are great when they work, and very horrible when they don't.
- se85 14y agoI don't see how this is any different for "OOP" though (or anything in life for that matter)? Things are always great till they don't work, and usually are absolutely horrible when they don't. I see your pipe dream on a daily basis as do many other competent functional programmers so I have to disagree with your entire argument which seems to more related to human error than programming paradigms getting in the way.
- chousuke 14y agoCould you explain why a monad is unencapsulated? As far as I can tell, using monads is a far superior way to encapsulate state, since it's impossible to use the state without also operating within the type universe that you've defined for your stateful calculations. Therefore, you can trivially tell if a piece of code is relevant to the state of your program, and it's enforced at compile-time. Further, since the actual state values are immutable, you can store references to them indefinitely. In most OOP languages, the whole concept of a "state at this point of execution" is completely unsupported, and that state is inaccessible to the programmer. Edit: I wrote this assuming we're talking about a sufficiently advanced static type system here, such as Haskell's. I've implemented monads in Clojure and while they can be useful, of course in a dynamic language they provide less safety since it's trivial to escape the monad.
- deleted 14y ago[deleted]