Functional programming: A step backward

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

Originally posted at Infoworld by Andrew Oliver, this is article is a little controversial, especially if you are a fan of functional programming, which is all the rage right now; that said, it’s interesting to read his take on it considering that he isn’t not exactly a fan.

Functional programming languages will have a place in general application development when we can read their code at a glance

functional programmingUnless you’ve been living under a rock, you know functional programming is all the rage among the so-called alpha geeks. Perhaps you already use a functional programming language. If you use a more conventional language like Java or C#, you’re probably aware it has functional programming features in store. While this brave new world is upon us, and before we take things too far, it might be a good time to pause and reflect on the appropriateness of functional programming for everyday application development.

What is functional programming? The simple answer: Everything is a mathematical function. Functional programming languages can have objects, but generally those objects are immutable — either arguments or return values to functions. There are no for/next loops, as those imply state changes. Instead, that type of looping is performed with recursion and by passing functions as arguments.

The case for functional

Proponents often argue that functional programming will lead to more efficient software, while opponents argue the reverse is true. I find both claims equally doubtful. I could easily be convinced that functional programming will make writing compiler optimizers more difficult or that the JIT compiler for functional code will be slower than the equivalent compiler for traditional code. There are close mappings between imperative programming languages and the underlying hardware support, but these don’t exist for functional languages. As a result, the compiler for a functional language has to work harder.

However, a good optimizer should be able to translate a functional programming closure, tail call, or lambda expression into the equivalent loop or other expression in a traditional language. It may require more work. If you’re up for a good 1,600 pages of reading on the subject, I recommend “Optimizing Compilers for Modern Architectures: A Dependence-based Approach” and “Advanced Compiler Design and Implementation.” Alternatively, you can prove this to yourself with GCC or any compiler that has multiple front ends and can generate the assembler.

The better argument for functional programming is that, in modern applications involving highly concurrent computing on multicore machines, state is the problem. All imperative languages, including object-oriented languages, involve multiple threads changing the shared state of objects. This is where deadlocks, stack traces, and low-level processor cache misses all take place. If there is no state, there is no problem.

There are many places where functional programming and functional programming languages are a great fit and probably the best approach. For pure mathematical calculation, functional programming is actually clearer than imperative programming. But for business software and other general application software, exactly the opposite is true. As Martin Fowler famously said, “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” The syntax of functional programming just isn’t readable at a glance.

A couple of code snippets will show you what I mean. An example from Erlang:

-module(listsort).
-export([by_length/1]).

by_length(Lists) ->
qsort(Lists, fun(A,B) -> A < B end).

qsort([], _)-> [];
qsort([Pivot|Rest], Smaller) ->
qsort([X || X <- Rest, Smaller(X,Pivot)], Smaller)
++ [Pivot] ++
qsort([Y || Y <- Rest, not(Smaller(Y, Pivot))], Smaller).

And one from Haskell:

-- file: ch05/Prettify.hs
pretty width x = best 0 [x] where best col (d:ds) =
case d of
Empty -> best col ds
Char c -> c : best (col + 1) ds
Text s -> s ++ best (col + length s) ds
Line -> 'n' : best 0 ds
a `Concat` b -> best col (a:b:ds)
a `Union` b -> nicest col (best col (a:ds))
(best col (b:ds))
best _ _ = ""

nicest col a b | (width - least) `fits` a = a
| otherwise = b
where least = min width col

Man versus machine

Any halfway decent programmer can quickly glean the general intent of most imperative code — even in a language he or she has never seen. While you can certainly figure out what functional routines do by looking at them, it may not be possible in a glance. Unlike imperative code, functional code doesn’t map to simple language constructs. Rather, it maps to mathematical constructs.

We’ve gone from wiring to punch cards to assembler to macro assembler to C (a very fancy macro assembler) and on to higher-level languages that abstract away much of the old machine complexity. Each step has taken us a little closer to the scene in “Star Trek IV” where a baffled Mr. Scott tries to speak instructions into a mouse (“Hello computer“). After decades of progress in making programming languages easier for humans to read and understand, functional programming syntax turns back the clock.

Functional programming addresses the concurrency problem of state but often at a cost of human readability. Functional programmming may be entirely appropriate for many circumstances. Ironically, it might even help bring computer and human languages closer together indirectly through defining domain-specific languages. But its difficult syntax makes it an extremely poor fit for general-purpose application programming. Don’t jump on this bandwagon just yet — especially for risk-averse projects.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone

25 Comments

  • “The code is ugly, so don’t use it” is a very unconvincing argument against using functional programming (FP). His other points seem to favor FP.

    • Zecc says:

      True, but the argument isn’t “the code is ugly, so don’t use it”.

      It’s “the code is harded to read and therefore maintain, so don’t use it”.

  • llayland says:

    The code examples would be a lot easier to read with proper indentation. It would also be good to see the same problem solved in an imperative language for comparison.

    “looping is performed with recursion” – recursion forms the base of looping, but it is good practice to hide primitive recursion behind a function that does the looping for a specific purpose. For example: map is used to get a copy of a list with each member modified by a function.

    “Any halfway decent programmer can quickly glean the general intent of most imperative code — even in a language he or she has never seen” – Could any halfway decent functional programmer get the intent of imperative code more easily than their imperative conterpart would get the intent of functional code?

  • James Iry says:

    Stripping whitespace is to make code seem unreadable is a dick move. Especially in Haskell where, like Python, whitespace is significant.

    Not posting equivalent imperative code for comparison is also a dick move. I find the Erlang functional Quicksort emminently more grockable than an imperative one, and I’ve written both many times. And have you ever tried writing a proper pretty printer imperatively? The Haskell code is a breeze to understand in comparison.

  • Kevin says:

    If I open an electronic device, I may not be able to understand every bit of the device, especially out of context. However, a well-trained electrical engineer would be able to understand the pieces and the “grammar” of the board. Likewise, a well trained software engineer with a functional background would be able to understand the code, especially with context. I am not for unnecessary complexity, but I find it worrying that there seems to be a growing trend of “coding to the lowest common denominator”; we are software engineers; what we do is complicated. Sometimes, the right tool for the job is complicated.

  • gar1t says:

    Great start! I can’t wait for the followup installations — which will presumably include snippets from an imperative language — say, Java — to finish off the point that functional languages necessarily make code hard to read.

    Heck, here’s one:

    http://www.vogella.com/articles/JavaAlgorithmsQuicksort/article.html

    So clean and simple! Any halfway decent programmer can at-a-glance know what’s going on there. No surprise really, as Java is well reputed for creating bug free code. And so easy to debug!

    What’s most impressive is how Mr. Oilver completely dismantled functional programming — and it’s 50 year history — in just over 700 words!

    Three words: InfoWorld-is-back!

  • mortoray says:

    While I do agree that Haskell and Erlang have perhaps made some poor syntactic decisions, I don’t think this should count against functional programming as a whole. In cases where you wish to have evaluate something, functional programming often provides a clearer approach (or could at least). But in cases where you need an imperative algorithm I find functional programming tends to falter. Ideally a language would find a way to integrate both constructs efficiently and avoid the symbol soup.

  • eche says:

    Precision: Human readability is of course a main point, if not The main point, because that’s central for complexity management, but don’t be confused, one thing is human readability, other much different thing is human imprecision, inaccuracy, vagueness, looseness. Taking as an example the layman human language as the most human ”understandable” of all, it’s at the same time the most imprecise of all. Then I think we need many languages, as in OSI model, the deeper the more mathematical, the shallowest the more imprecise and human. There is no “THE” language.

  • kciesielski says:

    Author complains about poor readability and maintainability of business code in functional style, then he gives two examples of code which is hardly “business”. As other people say, the only convincing argument would be a comparison between some imperative and functional implementations. With given snippets, the article is worth nothing. Guy should check Greg Young’s recent talk at SkillsMatter where he presented that modeling business domain with events in functional style is, in fact, much more elegant and natural. Domain model is all about verbs and people start to understand this.

  • local says:

    So your beef with functional languages is that the nice, declarative pattern matching has insufficiently C-like syntax?
    This is like claiming that Italian is incomprehensible because you, an English speaker, cannot understand it at a glance.

  • […] Functional programming: A step backward (jelastic.com) […]

  • Artuian says:

    we’ll some people exactly try to address your point. check out mythryl.org for an attempt to create an ml-derivative with c-syntax and easier readability to c-trained programmers.

  • redraiment says:

    The guy who only know English also can’t understand Chinese, and both English and Chinese are human language…

  • […]   英文原文:Functional programming: A step backward […]

  • Jason says:

    Readability is totally subjective! If you’ve programmed imperatively for years (or decades), coding problems probably seem to be naturally composed of for loops and conditionals as if they were platonic ideals. But a functional programmer of equivalent experience sees them just as naturally composed of maps, filters, folds, etc.

    Functional programming is not less readable, you’re just less familiar with it! A moment’s honest reflection should confirm this.

  • elnopintan says:

    I find Erlang version rather easy to understand. It sais, qsort of an empty list is the empty list and
    qsort of a list is the qsort of the elements smaller than pivot conctanated with pivot and the qsort of the elements bigger than pivot. And there is no need of comments as in the java version.

    • freebzh says:

      I agree… I don’t get what is not readable here… Some groovy code are purely OO and not readable if you don’t have the grammar …

  • It’s akin to an English speaker making an essay on how Japanese is difficult to read because it’s nothing like the languages they happen to be familiar with. Claiming something is more difficult to read or understand based on superficial exposure is asinine.

    Also, it’s quite clear that the author has no experience with FP whatsoever, as explicit recursion is something that’s seen very rarely in FP code. Most iteration is abstracted into higher order functions such as map, filter, reduce, and etc.

    FP languages also make it much easier to reason about code. Thanks to immutability you can reason about a piece of code in isolation without having to be aware of the state of the whole application.

    Finally, FP code is inherently more readable because it’s declarative in nature. In an imperative language you’re mixing what you’re doing with how you’re doing it, and it’s up to the reader to separate the two.

  • Chris Turner says:

    Three years ago I would have totally agreed with you. After 15 years doing imperative programming (using C, C++ and Java) I would have looked at that functional code just as you did and say WTF!

    However, I’ve spent a lot of the past three years doing functional style programming using Scala and more recently Haskell and Clojure. I can now pretty much look at any functional code and understand at a glance what it does.

    Please don’t confuse your lack of familiarity and time spent with the functional paradigm as being functional programs are hard to understand.

  • Tony Morris says:

    Haha, that was biggest load of nancy-pants, no fucking clue, complete bullshit that I have read so far in 2013. Can anyone top it? Dare ya! Imaginations are awesome. Go on, do better than this garbage!

  • […] Functional programming: A step backward (jelastic.com) […]

  • Hugh says:

    As an experienced programmer with almost forty years under my belt and having coded in machine code, assembler, C, APL, PL/I, Cobol, Java, C#, Pascal etc I must ask how you ascertain that imperative code is more “readable” than declarative code?

    SQL is much closer to functional code than imperative code, yet is incredibly popular, well established, well standardized and read and written by hordes of developers every day.

    Humans are incredible and daily, persistent, driven exposure to functional languages will soon lead to intimate fluency.

    All I will say is that comments are still very much a neglected facet of programming and a disciplined practice of routinely including accurate literate comments in source code is one of the best ways to improve code quality.

    If functional code is well commented I think many of your fears will evaporate.

Leave a Reply

Subscribe to get the latest updates