I’m curious about this because I recall before learning any functional languages, I thought them all horribly, awfully, terribly unreadable. Now that I know Haskell and f#, I find it takes a little longer to read less code, but that little code does far more than an equivalent amount would in an imperative language, so it feels like a net gain and I’m not extremely practiced in functional.
Here’s my question, I constantly hear from OOP folks that functional style is terribly unreadable. I’m curious if this is the case and I’m deluding myself, or if they took the time to learn a functional language, the whole style would no longer be more unreadable than OOP?
Has anybody seen any evidence or got any anecdotes where they saw this go one way or another with frequency enough to possibly say? If writing functionally really is of lower readability then I don’t want to keep using it, but I really don’t know if that’s the case or not..
4
Code readability is very subjective. Because of this, different people would consider the same code readable or unreadable.
An assignment, x = x + 1
sounds weird to a mathematician, because an assignment looks misleadingly similar to a comparison.
A simple OOP design pattern would be totally unclear for someone who is not familiar with these patterns. Consider singleton. Someone would ask “Why do I need a private constructor? What is the mysterious method getInstance()
? Why don’t we make a global variable and assign an object there?”
The very same applies to an FP code. Unless you know the logical patterns behind the scenes, it will be very difficult even to understand something very basic, e.g. how to pass a function as an argument to another function.
Having this said, one should understand that FP is not a silver bullet. There are many applications where FP would be difficult to apply and therefore, it will lead to a worse readable code.
1
Short answer:
One of the elements which make people say that functional programming code is difficult to read is that it gives preference to a more compact syntax.
Long answer:
Functional programming itself cannot be readable or unreadable, since it’s a paradigm, not a style of writing code. In C# for example, functional programming looks like:
return this.Data.Products
.Where(c => c.IsEnabled)
.GroupBy(c => c.Category)
.Select(c => new PricesPerCategory(category: c.Key, minimum: c.Min(d => d.Price), maximum: c.Max(d => d.Price)));
and would be considered readable by any person with enough experience in Java, C# or similar languages.
The language syntax, on the other hand, is more compact for many functional languages (including Haskell and F#) compared to popular OOP languages, giving a preference to symbols rather than word in plain English.
This applies to languages outside FP as well. If you compare popular OOP languages to some less popular which tend to use more English words, the last ones would feel easier to understand for people with no programming experience.
Compare:
public void IsWithinRanges<T>(T number, param Range<T>[] ranges) where T : INumeric
{
foreach (var range in ranges)
{
if (number >= range.Left && number <= range.Right)
{
return true;
}
}
return false;
}
to:
public function void IsWithinRanges
with parameters T number, param array of (Range of T) ranges
using generic type T
given that T implements INumeric
{
for each (var range in ranges)
{
if (number is from range.Left to range.Right)
{
return true;
}
}
return false;
}
In the same way:
var a = ((b - c) in 1..n) ? d : 0;
could be expressed in an imaginary language as:
define variable a being equal to d if (b minus c) is between 1 and n or 0 otherwise;
When shorter syntax is better?
While more verbose syntax is easier to understand for a beginner, more compact syntax is easier for experienced developers. Shorter code means less characters to type, which means more productivity.
Especially, it really doesn’t make sense forcing a person to type a keyword to indicate something which may be deduced from the syntax.
Examples:
-
In PHP you need to type
function
before every function or method, with no specific reason to do it. -
Ada always horrified me for forcing the developers to type lots of English words, especially since there is no correct IDE with auto-completion. I haven’t used Ada recently and their official tutorial is down so I can’t give an example; if anybody has an example, feel free to modify my answer.
-
The syntax
1..n
, used in many FP (and Matlab), could be replaced bybetween 1, n
orbetween 1 and n
orbetween (1, n)
. Thebetween
keyword makes it much easier to understand for people who are not familiar with the language syntax, but still, two dots are much faster to type.
8
I think one of the reasons is that functional programming tends to work with much more abstract concepts. This makes code shorter and more readable for people who know and understand the concepts (because they aptly expresses the essence of the problem), but it is unreadable for people who are not familiar with them.
For example, for a functional programmer it is natural to write a code that can fail at different points within the Maybe
monad, or Either
monad. Or, to write a stateful computation with the help of the State
monad. But for someone who doesn’t understand the concept of monads, this all seems like some kind of black sorcery.
So I think it’d be reasonable to use bits of functional programming even in a team of OOP people, as long as one use concepts that are easy to understand or learn, like mapping over a collection with a function or closures.
(And of course, it also depends on the programmer who wrote some piece of code. You can write horribly unreadable code in any language, as well as you can write in a nice and clean style.)
Readability has nothing to do with the paradigms, models and such. The more code reflects the semantics of your problem domain, the more it is operating a terminology and idioms of such a problem domain, the more readable it is.
This is the reason why OOP code is not that readable at all: not that many real world problems are naturally expressed in terms of hierarchical taxonomies. Objects passing messages to each other is a weird concept, and it is very far from anything “real”. Surprisingly, there are much more real world concepts that can be naturally mapped to the functional idioms. Problems tend to be defined declaratively, therefore a declarative solution is more natural.
Although, there are many other semantics that could be closer to the real world than a pure functional, pure OOP, pure dataflow or pure whatever would ever be. And due to this fact, a language-oriented approach to problem solving produces the most readable code, beating all the existing “pure” paradigms. With the domain-specific languages, every problem is expressed in its own natural terminology. And functional languages are slightly better than the OOP mainstream stuff in facilitating DSLs implementation (although, much better approaches are available).
0
Code readability is subjective. I’m sure that some people criticise it through lack of understanding. There are are naturally different idioms in the way common patterns are implemented. For example, the Visitor pattern doesn’t really make sense in a language with pattern matching.
Type inference can be a tricky feature. Usually, it’s a great accelerator of development, however, it can sometimes be difficult to figure out what types are involved due to the lack of context leading to confusing errors. This is not limited to what Functional Programming languages – I’ve seen it in C++ templates too!
Modern languages tend to be multi-paradigm. This includes both C# and F#. It is possible to write a functional style in C# and an imperative style in F#. The same people who criticise Functional languages probably write functional code in their object oriented language.
Commercial development in Functional languages is still relatively immature. I’ve seen a number of mistakes made that would be considered bad form in any language. Such as:
- Changing style as you learn the language (and not refactoring) leading to inconsistency.
- Too much in one file.
- Too many statements on one line.
1