Going Functional

7 December 2012 by Tomas Brambora - Category: Technical Articles

Introduction

Take a look at the following piece of code. What’s wrong with it?

myAwesomeFunction = (objects) ->
isGreat = false
for item in objects
if not item.isImportant
continue
if item.isGreat
isGreat = true
break
return isGreat

Does it go through all the items? No but, man, is that break on the last line easy to miss.
What does it do? Too bad a for loop has no return value. In order to get any idea you need to look into the loop code.

Now compare it with the following version:

myAwesomeFunction = (objects) ->
return _.any objects, (o) -> o.isImportant && o.isGreat

Even if you’re not familiar with the (wonderful, by the way) Underscore.js library, you can pretty much guess that myAwesomeFunction returns true iff objects contain a great important object.

Now, you could make a (valid) point that the original function is not a shining example of super-ninja programming skills. But that’s just another thing to point out: using for loops doesn’t push us, programmers, to be any clearer. Actually quite the opposite – it stands in our way by forcing us to remember we’re in a loop and we’ve to deal with it.

http://www.flickr.com/photos/sethw/381321976/sizes/m/in/photostream/

This guy may or may not have written it.

When it comes to expressing our intentions, a for cycle is a low level construct; unless you read the code thoroughly and really understand, you can’t know what the purpose of the loop is. It can filter something out or transform all the items in the list. It can signal whether a certain item is present. Frankly, for all I know it can brush your teeth and sleep with your wife.

It’s just too powerful. Too universal.

Now, in case CoffeeScript (or JavaScript) is your language of choice, chances are you’re not writing the type of software where speed is essential. Which means (or should mean, anyway) readability beats raw speed. Hands down.¬†And that’s when functional programming saves the day.

In the next article of this series, we’ll take a look at the ‘map’ function.


« - »
COMMENTS
  • Jared

    To do this in JS, it can be as simple as

    var arrayContainsGreatImportantObject = objects.some(function(element) {
    return element.isImportant && element.isGreat;
    });

    • Tomas Brambora

      Nice, I didn’t know about ‘some’!
      (I’m just used to Underscore ’cause its code is a pleasure to look at & it works across all the various weird JS implementations.)

  • Simon

    Yes, higher-level iterators like map/filter are very useful, though their value depends greatly on the language being used. CoffeeScript, as you’ve demonstrated, is *very* good for this, and I’m also very fond of Python’s list iterator functionality.

    Unfortunately, I frequently have to work in Java, which is pretty much the opposite – you *can* do this kind of thing, but it usually ends up three times the size of the simple for-loop.

    • Tomas Brambora

      Python is a nifty little language, yes. But I have to say after some time spent with JS (and CS and Haskell and such), I find it hard to express myself fluently in a language that doesn’t have full-blown anonymous functions. It’s just such a powerful and elegant concept. And CS adds really convenient syntax to that (come on JS, seriously, ‘function’ is 8 chars, who wants to type or read that all the time).

      Also, you’ve pointed out the exact reason why I’m avoiding Java (Steve Yegge wrote a famous post ’bout that: http://steve-yegge.blogspot.cz/2006/03/execution-in-kingdom-of-nouns.html).

  • Aa

    this is the real, non functional code
    myAwesomeFunction = (objects) ->
    isGreat = false
    for item in objects
    if item.isImportant && item.isGreat
    isGreat = true
    break
    return isGreat