One of the main benefits, at least to me, is that code written in a functional style is much easier to understand.
I have seen baffling code in FP (Clojure and Haskell). I have seen baffling code in OOP (C++, Java, and Ruby). It turns out, you can write baffling code in any language paradigm. The more experience I get, the more I think we should stop trying to umbrella ourselves under a single paradigm, and borrow ideas as needed from all of them.
I struggle to consider what we do software “engineering” because here’s how similar discussions would appear in other engineering fields:
Using DC is better than AC!
Helium is last year’s noble gas. Use neon instead!
Only your grandma uses wheels. Everyone is using jet engines now!
I have seen baffling code in FP (Clojure and Haskell). I have seen baffling code in OOP (C++, Java, and Ruby). It turns out, you can write baffling code in any language paradigm.
That is very true, especially with the terseness of some FP code.
However, the author was talking about the ease of understanding that comes from not needing to keep track of side effects in your head. That is, understanding the computational model—which is different than readability.
Side effects are only part of complexity and state though. The convoluted FP code I’ve dealt with involved funneling data through layers and layers of operations, and keeping track of where you were in the data transform to tie in new program behavior. In FP state is still there, but it’s just ephemeral (data transforming into other data) and structural (composition of functions and the nature of how program flow emerges out of it).
Those are good points. There are impediments to understanding code beyond side effects and I’ve seen code similar to what you’re referencing.
I’ve found that types (or even contracts) can provide most of the information needed to determine how some new functionality fits in an existing composed transform. Breaking apart a transform to run a portion of it just to see what the data looks like at that point should not be necessary and does feel similar to debugging OO code. I have only experienced that with dynamically-typed FP languages.
It’s also not unreasonable that grokking the transform takes a minute. In some cases, that transform essentially is the program—or at least a substantial feature of it.
I struggle to consider what we do software “engineering” because here’s how similar discussions would appear in other engineering fields:
Using DC is better than AC!
Helium is last year’s noble gas. Use neon instead!
Only your grandma uses wheels. Everyone is using jet engines now!
Not sure if you are being sarcastic, are you not aware of the war of the currents? Google Tesla vs Edison. Your hypothetical examples are actually very real. Including the last one.
Perhaps the lesson to learn from others fields is: each has its own advantages and disadvantages, it’s about knowing them. Although some technologies do become obsolete and objectively beaten by others. CFCs, medical Lead, bleeding as a treatment, etc. Come to mind.
Note the lack of context or application in all those headline-like lines. I used extreme sarcasm to point out that the value of many technical solutions matter require understanding of their context and application.
I don’t think FP vs OOP is the dichotomy at all. FP is functions-are-data, and OOP is class/object-based multiple dispatch. You can have both or neither! That’s why we can pick and choose ideas.
This reminds me of the following comment by Philip Greenspun: Technical people have traditionally met these challenges … by arguing over programming tools. The data model can’t represent the information that the users need, the application doesn’t do what what the users need it to do, and instead of writing code, the “engineers” are arguing about Java versus Lisp versus ML versus C# versus Perl versus VB. If you want to know why computer programmers get paid less than medical doctors, consider the situation of two trauma surgeons arriving at an accident scene. The patient is bleeding profusely. If surgeons were like programmers, they’d leave the patient to bleed out in order to have a really satisfying argument over the merits of two different kinds of tourniquet.
But maybe we should step it up a level and insist that functional programming is programming with only functions and no values at all. This is known as pointfree or tacit programming, and there are many languages in these families. To name some families in particular, Forth and APL are practical approaches to this style, but there have also been formal approaches with combinators and categorical logic.
Isn’t Smn Theorem basically available for all Turing-complete languages? The same goes for currying and closuring over values/names?
But maybe we should step it up a level and insist that functional programming is programming with only functions and no values at all.
That would pretty much remove all eagerly evaluated languages like Lisps or MLs. Also tactic programming do not requires everything to be function as Wiki example of sum in Haskell sum = folds (+) 0 uses value 0.
That was a nice piece of trolling given it had some truth mixed in with it. There’s definitely cult-like behavior around some of these languages. That said, there’s individuals and companies using them because they have real benefits. @Yogthos already commented on it with some of them. Destroyed the original claim, too.
I’ll just highlight a few traits of CL as a non-CL user that impress me. Powerful/easy macros, any paradigm not already supported is easy to add (esp adding aspects just took a library), REPL environments for fast development, optimized compiles for delivery, can compile a single function after changing it, and live updates to running environment. If you’re correct, then C, C++, Java, .NET, PHP, Python, etc. had all these capabilities as they got popular since CL was nothing special. Alternatively, these are all useless with only masochistic zealots using them while those other languages, their IDE’s, and ecosystems never adopted or attempted any of those capabilities.
The additions of CL-like features to some of those languages, their IDE’s, and external projects they keep attempting suggests there’s some actual advantages to CL’s design and capabilities. Its capabilities from the 1980’s or earlier (i.e. Genera). Being so far ahead and so flexible attracts many bright minds who become obsessed with it. It also attracts ordinary developers who simply want its capabilities, in CL or another preferred language. A combination of crowds with varying motivations. That’s my theory.
I agree with the overall notion in the article, but some of the examples given are just terrible. Avoiding global variables isn’t something specific to lisp or functional programming; it’s just called good programming. Even in an unabashedly imperative Algol-like language like Lua, experienced programmers refuse to use globals in nontrivial codebases, because it makes things harder to understand.
I have seen baffling code in FP (Clojure and Haskell). I have seen baffling code in OOP (C++, Java, and Ruby). It turns out, you can write baffling code in any language paradigm. The more experience I get, the more I think we should stop trying to umbrella ourselves under a single paradigm, and borrow ideas as needed from all of them.
I struggle to consider what we do software “engineering” because here’s how similar discussions would appear in other engineering fields:
That is very true, especially with the terseness of some FP code.
However, the author was talking about the ease of understanding that comes from not needing to keep track of side effects in your head. That is, understanding the computational model—which is different than readability.
Side effects are only part of complexity and state though. The convoluted FP code I’ve dealt with involved funneling data through layers and layers of operations, and keeping track of where you were in the data transform to tie in new program behavior. In FP state is still there, but it’s just ephemeral (data transforming into other data) and structural (composition of functions and the nature of how program flow emerges out of it).
Those are good points. There are impediments to understanding code beyond side effects and I’ve seen code similar to what you’re referencing.
I’ve found that types (or even contracts) can provide most of the information needed to determine how some new functionality fits in an existing composed transform. Breaking apart a transform to run a portion of it just to see what the data looks like at that point should not be necessary and does feel similar to debugging OO code. I have only experienced that with dynamically-typed FP languages.
It’s also not unreasonable that grokking the transform takes a minute. In some cases, that transform essentially is the program—or at least a substantial feature of it.
Not sure if you are being sarcastic, are you not aware of the war of the currents? Google Tesla vs Edison. Your hypothetical examples are actually very real. Including the last one. Perhaps the lesson to learn from others fields is: each has its own advantages and disadvantages, it’s about knowing them. Although some technologies do become obsolete and objectively beaten by others. CFCs, medical Lead, bleeding as a treatment, etc. Come to mind.
Note the lack of context or application in all those headline-like lines. I used extreme sarcasm to point out that the value of many technical solutions matter require understanding of their context and application.
On one of the programming forums someone wanted Scheme code for function:
So as this obvious homework I have given them correct functional code:
I hope that they got good grade ;)
Jokes aside - closures and objects are equivalent
I don’t think FP vs OOP is the dichotomy at all. FP is functions-are-data, and OOP is class/object-based multiple dispatch. You can have both or neither! That’s why we can pick and choose ideas.
This reminds me of the following comment by Philip Greenspun:
Technical people have traditionally met these challenges … by arguing over programming tools. The data model can’t represent the information that the users need, the application doesn’t do what what the users need it to do, and instead of writing code, the “engineers” are arguing about Java versus Lisp versus ML versus C# versus Perl versus VB. If you want to know why computer programmers get paid less than medical doctors, consider the situation of two trauma surgeons arriving at an accident scene. The patient is bleeding profusely. If surgeons were like programmers, they’d leave the patient to bleed out in order to have a really satisfying argument over the merits of two different kinds of tourniquet.
The last time we had this particular flamewar, I listed off some criteria:
But maybe we should step it up a level and insist that functional programming is programming with only functions and no values at all. This is known as pointfree or tacit programming, and there are many languages in these families. To name some families in particular, Forth and APL are practical approaches to this style, but there have also been formal approaches with combinators and categorical logic.
Isn’t Smn Theorem basically available for all Turing-complete languages? The same goes for currying and closuring over values/names?
That would pretty much remove all eagerly evaluated languages like Lisps or MLs. Also tactic programming do not requires everything to be function as Wiki example of
sum
in Haskellsum = folds (+) 0
uses value0
.Functional programming is all about in-group signaling and sunk costs
That was a nice piece of trolling given it had some truth mixed in with it. There’s definitely cult-like behavior around some of these languages. That said, there’s individuals and companies using them because they have real benefits. @Yogthos already commented on it with some of them. Destroyed the original claim, too.
I’ll just highlight a few traits of CL as a non-CL user that impress me. Powerful/easy macros, any paradigm not already supported is easy to add (esp adding aspects just took a library), REPL environments for fast development, optimized compiles for delivery, can compile a single function after changing it, and live updates to running environment. If you’re correct, then C, C++, Java, .NET, PHP, Python, etc. had all these capabilities as they got popular since CL was nothing special. Alternatively, these are all useless with only masochistic zealots using them while those other languages, their IDE’s, and ecosystems never adopted or attempted any of those capabilities.
The additions of CL-like features to some of those languages, their IDE’s, and external projects they keep attempting suggests there’s some actual advantages to CL’s design and capabilities. Its capabilities from the 1980’s or earlier (i.e. Genera). Being so far ahead and so flexible attracts many bright minds who become obsessed with it. It also attracts ordinary developers who simply want its capabilities, in CL or another preferred language. A combination of crowds with varying motivations. That’s my theory.
I agree with the overall notion in the article, but some of the examples given are just terrible. Avoiding global variables isn’t something specific to lisp or functional programming; it’s just called good programming. Even in an unabashedly imperative Algol-like language like Lua, experienced programmers refuse to use globals in nontrivial codebases, because it makes things harder to understand.
fascinating idea. thanks for posting.
Good article - here’s a link to the paper by Sosis and Bressler that seems to be broken in the article http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.500.5715&rep=rep1&type=pdf
Thanks. Fixed the link.
What functional programmers do
Looking interesting; is there an RSS feed?
Looking at the source it seems this is a JavaScript site with Gatsby. They need to do this if they want a feed: https://www.gatsbyjs.org/docs/adding-an-rss-feed/