Thursday, August 21, 2014

Functional Programming: What, Why?

I've been using functional programming for a very long time, mostly because I'm a UI engineer, and the languages UI devs use often have functional capabilities. JavaScript, ActionScript, etc.

Wait...that's not entirely true. To be precise, I took first-class-functions for granted as an occasionally useful capability, usually event handling or sorting. Imperative programming and OOP rule the roost everywhere I've ever worked right up to today. When I do see functional forms, it's usually from a contract ActionScript or JavaScript developer and it tends to look something like this:
ab = function ( afunc ) { return afunc ( function ( x ) ); } ( );
I'd ask, "why did you do it that way," and get, "because that's functional programming." I'd reply, "aside from telling me, 'I do it because that's what it is,' what specific reasons do you have?"

Not once, in all my years, have I gotten a straight answer to this question. Nobody has ever sketched out a rough equivalent in OOP and pointed out the pros and cons. In fact, the more cryptic the function, the more satisfaction seemed to come from writing it; huge paragraphs of functions feeding anonymous functions from some global variable somewhere in some imported script. The fact that it would confuse me almost seemed desirable.

In the end, based on observation and discussions with people I've worked with at companies big and small, again right up to today, I had good reason to believe that functional programming is an oft-abused stylistic preference. When you grow up you go to OOP. One guy, who has taught comp-sci at a prestigious university and written software you may even have purchased, said that functional coding in the average programmer's hands makes a cryptic and impossible-to-debug mess that usually needs to be refactored. The fact that some of this guy's work is reputable cryptology programming makes that sort of funny to me.

But...is that all there is, is there nothing more? Why are languages like Scala, Clojure, the mechanisms offered by Groovy, and so forth, catching fire?

Qualifier: optimizations not found in many imperative languages, such as memoization, tail optimization for recursion, lazy evaluation, mutable vs. immutable, and so on, aren't what this blog is about; of course they matter, but this post is focused on the writing of code.

Anyway, off to the papers, forums, and Kindle store I went.

In general, the introduction is always the same; functional programming is about using higher order functions, those being, functions that take and return functions. It makes your code more succinct. Write less code, get superior results.

Pithy quotes abound, like this one from  C.A.R. Hoare's 1980 ACM Turing Award Lecture:
"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies."
They all go on to describe how such and such languages already have the higher-order function capability, Haskell has been around for decades, and things like "lamdas" are coming to Java.

Then the examples. "You could write this sequence of operations this way...but if you use this language and these higher-order function, you could write it this way." And then you start seeing the word "reduce" a lot, with no real idea what exactly reduce does...ok let me go look that up...hmm ok collection operations, and so on...I'm drifting. Back to the functional stuff.

The "but...this way" is always shorter and more succinct. But they omit the implementation of the higher order functions, resulting in my previous drift...which if they placed right under the "shorter, more succinct," code, would appear to remove that benefit (particularly as higher order functions often use other higher order functions...which can be VERY confusing to unravel).

Examples: in Clojure:
( reduce + ( map inc mylist ) )
In C# functional style:
result = mylist.Select ( i => i + 1 ).Sum ( );
In C# imperative style:
int sum = 0; 
foreach ( int i in mylist )
{
   sum += ( i + 1 );
}

Ok...sure, both the Clojure and C# functional are one line. The C# imperative one is five. But I don't need to see any other implementations in the imperative example to know what this does (other than List, but that's true for all three examples). What is the implementation of reduce, map, Select, Sum, etc?

Argument: "that's the point, you don't need to know that. Functional Programming delegates more optimization and utility functions to the runtime."

Sure, this is true for languages that offer such robust higher-order utility. But what if your language doesn't have a robust list of these amazingly useful and succinct higher order functions, as pointed out in Marijn Haverbeke's excellent book, Eloquent Javascript, a Modern Introduction to Programming:
"Unfortunately, a standard JavaScript environment comes with deplorably few essential functions, so we have to write them ourselves or, which is often preferable, make use of somebody else's code."
And...what if I just defined a couple of static functions in OOP and fed that list to them? I could reduce that C# imperative example to this:
int sum = ListIterator.sumOfElementsIn ( myList, 0 );

No higher order functions, one line, very succinct.

So on the surface (keep reading, I get back to this later), I tended to reject the most commonly given rationales for functional programming as being primary:
  • Make code easier to write.
  • Make code more expressive (reduce need for comments etc.). 
Anybody can write expressive code in any language--well, except maybe Objective-C--and anybody can write unbelievably cryptic code in any language. Some of the functional programming production code I have seen is absolutely impossible to unravel, even the developer can't do it a few days after writing it, and this isn't just the odd incompetent, it's pretty common.

So what else do we have?
  • Make code more about the problem and less about the mechanics. 
This is a matter of expressiveness, and the availability of more robust higher-order functions. Still not really doing it for me; again, somebody has to write those libraries/functions, and beyond a certain point, that person may very well be you, particularly if you use JavaScript.

So, moving along:
  • Reduce the objects I need to be aware of and use. 
Here at last I found some ground to stand on in favor of the functional paradigm. From Neal Ford's Functional Thinking: Paradigm Over Syntax, I got this blurb, and it's not hard to look over a few languages and confirm it:
"In the OOP world, developers are encouraged to create unique data structures, with specific operations attached in the form of methods. Functional programming languages don't try to achieve reuse in quite the same way. In functional programming languages, the preference is for a few key data structures (such as list, set, and map) with highly optimized operations on those data structures. To utilize this machinery, developers pass data structures plus higher-order functions to plug into the machinery, customizing it for a particular use."
This is later backed by a quote from such amateurs as Alan Perlis, the first recipient of the Turing Award:
"It is better to have 100 functions operate on one data structure than 10 functions to operate on 10 data structures."
I found this to be VERY enlightening, my first real "ah HAH" moment. One of the things I shy away from in Java development is, "well what we'll do is extend HashMap and implement with these additional, overridden/overloaded functions...or maybe we don't need the hash at all, so we'll implement a simplified two-array map object..."

Hmm...why don't we just create a function that accepts the map as-is and does what we need, so we're not endlessly creating new kinds of maps? And if we can submit a function along with it, we can even provide the processing. Sort of look at the problem inside out from OOP. 

Hey, how about that. I've been instinctively dabbling in functional thinking all along; favor course-grained reuse mechanisms, avoid highly specific ones when you can.

Here's some of those simple examples you need to get you thinking, again from Eloquent JavaScript:

First, a very standard routine to log things from an array, imperative style:
var array = [ 1, 2, 3 ];
for (v ar i = 0; i < array.length; i++ ) {
  var current = array [ i ];
  console.log ( current );
}
Ok...make it a function. Still imperative, but more succinct.
function logEach ( array ) {
  for ( var i = 0; i < array.length; i++ )
    console.log ( array [ i ] );
}
var array = [ 1, 2, 3 ];
logEach ( array );

Now we begin to see where higher-order functions fit in. What if I want to logEach index? What if I want to log the sum? Should I add params to the function argument so I can add different loops (or just do something different within the same loop based on the arg)? Write more functions specific to the kind of logging I want? Or some such similar solution?

If you think about it, that's a violation of DRY. I am constantly repeating the need to iterate. I need to sort-of turn it inside out: make the iteration the factored operation, and make the specifics of the iteration a matter of what I feed the factored operation.

Functionally, that looks like this (again from Eloquent JavaScript):
function forEach ( array, action ) {
   for ( var i = 0; i < array.length; i++ )
       action ( array [ i ] );
}
var words = [ 'Wampeter', 'Foma', 'Granfalloon' ];
forEach ( words, console.log );
Now we're talking. If used properly, you do in fact enable more succinct code, even without built-in higher-order functions. That second code block is two lines long and very succinct. And because I factored the courser-grained general "need for iteration of an array", I don't have to constantly write those loops.

Now we get to a point of divergence in my thinking; anonymous functions. This could be a result of just not seeing and using them every day.

If I want to do something different with my forEach, I can still do it nice and functionally. For instance, add up the array of numbers instead of log them, logging the result after the fact:
var numbers = [ 1, 2, 3, 4, 5 ], sum = 0;
forEach ( numbers, function ( number ) {
  sum += number;
} );
console.log ( sum );

To me, even in this little frag, the succinctness falls apart. That anonymous function just makes it a lot more cryptic. It would be a LOT clearer if that anonymous function had a name that added to the "readability" of the line. Doing it with the anon func sort of feels like submitting a hard-coded string to a function instead of a val from an enum or const, with a name that tells you what the purpose of that value is. This will force you to add a comment.

So, I would tend to say, less lines don't mean easier to read. Declare your functions as smartly named variables and use them by reference, exactly as you would any other var, if you intend to feed that function as an argument to a function that can serve many purposes (like an iteration function). 
var numbers = [1, 2, 3, 4, 5], 
    sum = 0,
    addTheNumbers = function ( number ) { sum += number; };

forEach ( numbers, addTheNumbers );
console.log ( sum );
Let's add operations, that imperative programming would typically implement with multiple loops, or a loop with some kind of if-then or switch qualifier, seeing the effect of course-grained on your code:
var numbers = [1, 2, 3, 4, 5],
    words = [ 'Wampeter', 'Foma', 'Granfalloon' ],
    sum = 0,
    addTheNumbers = function ( number ) { sum += number; };
forEach ( words, console.log );
forEach ( numbers, addTheNumbers );
console.log ( sum );
Nobody should have a problem understanding this. The lexical access makes "sum" interesting, but that's a JavaScript thing here.

Also notice; the forEach function can either perform the operation without returning anything if the operation passed in has the implementation (e.g. console.log), or it can return values, whatever is useful at the time. Imperative programming just doesn't work this way, and that can be a very hard notion to get your head around (or un-around and then around again) for an OOP/imperative programmer.

Mold the language to the problem, not the problem to the language. I get it.

So, there you have it; the conduit that finally got me away from just going through the functional motions, and actually "thinking" functional as a way of factoring a problem and writing code. Ever since, I have started seeing opportunities to do these sorts of things in my day-to-day work, and I have to say it's reinvigorated my programming.

As always, thanks for visiting.