Tracee Pettigrew - August 20, 2015
First let’s start with a disclaimer: This is by no means an argument on if taking a functional or object-oriented (OO) approach to your code architecture is better. To be honest, my exposure and true understanding of the power of functional programming is slightly limited.
However, despite my brief encounters with the functional programming paradigm, I strongly believe that its influence on modern programming languages has shaped the landscape for the better. What do I mean by that? In my opinion, the movement to support functional programming has significantly cleaned up modern languages, and in turn, improved the overall readability and maintainability of code.
For some background, I am an iOS Developer who loves Objective-C, is obsessed with Swift, and despises Java. I have some experience with Python and a little exposure to Scala. The majority of my opinions on this particular subject are based around the growth of Swift, which can be used functionally or imperatively depending on your whim; therefore, I will be using Swift to help me prove my points. Now on to the good stuff…
How verbose a programming language is impacts both the readability and maintainability of your code. Odds are the longer a snippet of code takes for you to read it, the longer it will take for you to discern what’s happening in it.
It’s my argument that languages that have adopted a functional feel keep the verbosity of their languages low, therefore, keeping their languages lightweight. One easy example is the declaration of “expanding” arrays. In Objective-C or Java, an array of Car objects would look like the following:
If we wanted to do the same in Swift, it would look like the following:
Note that in both the Objective-C and Java examples, I am declaring the type of array that I want twice. This is a fairly small point to nitpick; however, since we are emphasizing lightweight code, I felt it was appropriate to point out.
The main difference that I want to highlight is that mutability is not tied to individual classes in Swift, but instead is a construct of the language itself. To elaborate, if I were to explain to you that in Swift var meant that you can change an “item” and let meant that you couldn’t, the differences of the following two declarations becomes a bit clearer.
Now re-examining the Objective-C and Java, understanding the mutability of an array becomes slightly harder.
To come full circle, our code becomes verbose because of this. How? We are no longer granted an easy paradigm, such as let or var, to figure out whether our cars array can have more car objects added to it. Instead, we must know the particulars of each language (e.g. API for NSArray and NSMutableArray).
I have found that languages that aspire to support functional programming have an underlying uniformity to handling objects, whether an array, object, or function.
Readability is usually not the first thing that comes to mind when thinking about functional programming or a language that supports it. To the untrained eye, the syntactic sugars of a functional language can lead to diabetes. However, I believe that there are underlying themes that flow in languages that aim to support functional programming which can ultimately improve its readability.
Let’s examine the classic example of filtering an array. Admittedly, this is a trivial case but one that helps emphasize my point. In Swift, filtering an array to produce another can be done both imperatively and functionally.
In both examples, I am searching for a String which equals “Fit” so that I can add it to my new array, which I print later. Ignoring the amount of code needed to execute, it’s my opinion that the functional approach is much more readable. Excluding the $0, which may vary little for code comprehension, cars.filter(…) explicitly tells me that some sort of filtering will be happening on my array of Strings. The specifics of the filtering is left for what’s between the curly braces. The imperative approach, however, requires me to “digest” what’s happening.
Once again, this example is somewhat trivial. I am not exploring the “flairs” that Swift or Scala has which makes it faster to produce code but in turn, makes what’s happening somewhat oblivious to the reader. It’s my argument that all programming languages have these uniquities which require a bit of a learning curve when using advanced language features (e.g. operator overloading for concatenation of Sets in Scala vs. lambda declaration in Java 8).
The inevitability of a growing codebase makes maintainability an important quality attribute to any software company. Evolving your codebase to deliver new features can easily become a nightmare. Also, maintainability is often a shared responsibility that necessitates the need for everyone who is currently on team (and those to come) to contribute to keeping the code clean. Therefore, selecting a language is a pivotal decision.
In my opinion, selecting a language that flexes into both functional and imperative programming will help with maintaining code in the future. I recognize that “clever” code offered by functional languages can sometimes leave developers scratching their head as to what’s going on. I would argue that good commenting practices combat time wasted digesting what is happening in those circumstances. Instead, I see there being large wins to adopting languages with lightweight syntaxes and overarching themes which apply across types.
Once again, I may be biased on this subject due to my undying love of Swift. But I would love to hear your opinions on the matter.