Despite the headline, I think this is a critique of fp that is both informed and aims to be balanced. I am interested in reactions here.
…this is a critique of fp that is both informed and aims to be balanced.
It’s not. It’s trivial and insipid, hinging its main argument on the claim that “The syntax of functional programming just isn’t readable at a glance.” Whether or not code is readable at a glance is really dependent on a vast number of factors, and furthermore the author expects that we accept, unequivocally, this vague notion of “readability” being a critically important factor in choosing a language. I don’t always agree with Martin Fowler but I doubt he’d approach the argument with the same lack of nuance. Quoting him to bolster the point is an appeal to authority which doesn’t even hit the mark.
It’s easy to find more to criticize in this piece, but more generally I think we should stop with these OO vs. Functional programming articles–the reality is that it’s much more illuminating and meaningful to talk about specific choices in a given language or languages and compare and contrast what programming styles they enable or promote, or what therefore becomes difficult because of specific choices. I like reading about philosophies underpinning the structure of a language or the history of a language feature…etc. I agree with what sdiehl wrote: there are so many interesting dimensions to discuss–why bother with a piece like this?
It is hilarious as well, since the author quotes Quicksort in Erlang as hard to read whereas Quicksort in an imperative language like C is even worse to read and understand and most importantly, to get right. The argument is completely flawed.
While I don’t disagree with you about the problems in the article, I do feel like that C implementation of quicksort you linked to as an example of poor readability has readability problems primarily because of extremely poor variable naming, something which is easy to fix (though that’s perhaps not the only problem, but it is the one that will stand out the most to people). That kind of poor naming seems to be ingrained in C programming culture which is unfortunate. I write C code myself and I always use descriptive names anyway. I’m also not really sure I agree that implementing quicksort in C is hard to get right, at least not moreso then with most other imperative languages.
I think the readability problems with the functional implementations are primarily because of extremely poor function naming, which unfortunately seems ingrained in Haskell programming culture.
I doubt the names are poor, but rather, unfamiliar to a general audience. Most programmers don’t understand the theory from which they originate.
No, I think they’re badly named even within the theory. Too many symbols that would be better as words, and too much inconsistency just because of traditions in the field (e.g. “type constructor”).
“The syntax of functional programming just isn’t readable at a glance.”
I really hate syntax arguments. They hide systematic arguments.
For example, good object-oriented systems have the habit that everything happens somewhere else. This can be extremely confusing and hard to grasp at a glance (though not necessarily bad, systematically thinking). It has nothing to do with syntax, though.
Take my python fan advice as it is.
I think readability is not a critically important factor, but it is important as a lots of others. One of other important dimension is as believe how much immutability of data structures there is built in language (and here python is really poor)
[Comment removed by author]
To be fair, Python’s list comprehensions and generator expressions are functional features (map+filter), not imperative.
I agree, though, that in general “imperativeness” of code has nothing to do with readability, it seems that the author is more biased to it due to familiarity.
To be fair, Python’s comprehensions are profoundly unimperative. One of the many major weaknesses of this article is that imperative languages (even conservative stalwart Java) have been integrating functional concepts and constructs for years now, and there’s nothing even resembling a firm line anymore.
This feels like FUD mongering for Java devs. Actually, it’s worse, it’s FUD being spread to put a bandaid on fears someone might feel that they’re becoming obsolete. That means that the rhetorical bar it must jump over is subterranean.
Don’t jump on this bandwagon just yet – especially for risk-averse projects.
Can’t you just see someone justifying a decision to avoid thought in this manner? “Why are we going with Java?” “Well, I heard that functional languages have unreadable syntax—it’s just a fad anyway” If you want to go with Java, do it for thoughtful or at least honest reasons instead of justification found in intellectual junk food.
That’s actually what I sort of wish I could flag this article as: “intellectual junk food”.
There are so many interesting dimensions to talk about in comparative language discussion. Yet we always get hung up on these really lazy and subjective “readability” of lexical syntax nonsense. It’s just frustrating…
Anyone else bothered by the article’s constant characterization of imperative programming as “conventional”/“traditional” and functional programming as implicitly new and weird? First, characterizing functional programming as new or unusual is strange given that Lisp, the prototypical functional programming language, was first written in 1958. Second, such a characterization serves no purpose other than to bias the reader against functional programming languages without actually making an argument.
Not only that, he goes on to claim that functional programming is, syntactically, a step backwards. You can’t have it both ways–claiming it’s the hot new thing then arguing it’s outdated.
I believe assembly is hard to read, understand and write. Therefore imperative programming is a step backward. I haven’t written a single line of Swift, or Obj-C, therefore I can’t possibly understand it at a glance. Thus, OOP is a step backward.
Am I doing it right?
I was tempted to stop reading this after the weird “alpha geeks” comment in the first sentence. Turns out I should have listened to my instincts. I will leave it there, as the issues with this article have already been highlighted by others here.
Ironically (given his examples), ADTs and pattern matching are practical yet powerful concepts that I wish more imperativish languages would steal for themselves. I use them all the time when writing Swift, which is far more like Java in syntax and philosophy than either Haskell or Erlang (for better or worse).
This is far off the mark.
I will go this far: in small examples, imperative code is more readable and better matches what seems to be the more “intuitive” understanding. Recipes are written in an imperative style: do X, then do Y, then if condition C is true, do Z. You’ll even see goto in natural language instructions: “if C, return to step 7”. Most of us are used to imperative models, when it comes to relaying sequential instructions, and that makes imperative code more natural to us… when we’re dealing with small programs that can fit on a page.
Here’s the difference: a recipe in a cookbook might have 15 instructions, while a program can have hundreds to millions. That which is innocuous and very useful at the small scale (e.g. unrestricted goto) becomes a mess at the large scale. Small-scale readability isn’t a major concern, because both models (imperative and functional) are quite readable, in most cases, once a person gains familiarity with the languages and programming models involved. It’s the large scale that worries us, and at that point, you need compositions, and what composes better than functions? We need to group like behaviors with like in a conceptual hierarchy (because we can only fit ~7 things in short-term memory) and what is the most reliable way of doing that? Factoring a large program out into smaller ones, many of which (rarely all, but often most) can be modeled as stateless functions.
No language is “purely functional” in the academic sense, because managing and updating state is the program’s job. Functional programming isn’t about outlawing state; it’s about forcing you to write programs in which, unless the programmer is deliberately hiding something, knowing where there is state is relatively easy. In Haskell, you get that information in the type signature. That’s a huge win. I’ve argued before that Haskell is actually the best imperative language. You get small-block readability via do-notation (which seems “magical” but is actually easily translatable into something with precise semantics in terms of return and (>>=), the latter pronounced “bind”) and large-scale comprehensibility through the types.
“I could easily be convinced” is a great prefix for making the following statement(s) come off as fact for the casual reader. Going to have to remember that one..
I think this article isn’t well written, but I do agree that it’s hard for programmers who don’t know FP to approach a codebase written in it. Does anyone disagree with that?
I think it’s easy for programmers who actually understand OO well - those who “get” the value of polymorphism, SRP, and avoiding explicit branching. E.g. I think an experienced Smalltalk dev would have no trouble picking up Erlang or Haskell.
There are programmers who have trouble understanding FP codebases, but I’m not sure they’re distinguishable from outright bad programmers.
When learning any natural language, it is not immediately apparent how to express a particular idea. However, multilingualism has many benefits, including the benefit that you tend to express yourself better in all the languages you are familiar with. A lack of initial understanding shouldn’t detract from the merit of learning a new natural language (with natural language, it’s to be expected), so why is this a valid argument against the unfamiliar syntax of functional programming languages?
Reading this article made me think about how English has become a lingua franca for international business, and I’ve realized that Algol-like syntax has become a lingua franca for programming, and as such, it’s preferred over lesser-known alternatives. Fortunately, programming languages have been evolving quickly.
From what I’ve seen, people really enjoy using more functional constructs in their imperative languages. Lambdas, Java Streams, LINQ, and list comprehensions all come to mind. For the most part, these features were introduced relatively recently into these languages using syntax that feels endemic to the host language, which helps ease people into adopting these new tools.
This brings about an interesting relationship between industry-standard and lesser-known programming languages today. These lesser-known languages tend to be where a lot of interesting ideas originate, and by some heuristic, the fittest of these ideas tend to propagate into popular imperative languages. I think this relationship benefits enthusiasts of both language types. Industry-standard language enthusiasts get these cool new features in their languages, and the enthusiasts for the lesser-known languages find working in these standard languages a little less unpleasant, and can channel any new pain toward figuring out new solutions for these industry-standard languages to integrate.
I don’t think it’s accurate to classify functional languages as a step backward, since it’s these same languages which have been helping to provide a rich ecosystem which has been pushing imperative languages forward.
TL;DR: Imperative languages are a lingua franca for programming. Functional languages help these imperative languages become better over time. This relationship benefits both functional and imperative programming languages.