The “Anti-For” Campaign

Recently, there has been an effort launched called the “Anti-If Campaign” in which they deride the use of if statements and instead, focus on Object Oriented Principles in order to create more flexible designs.  Now certainly, I have a sympathetic ear to this cause as I’ve seen code that literally walks off the side of the screen due to nesting of if statements.  Pattern matching to me, especially at the top level of the function is actually quite beautiful in a way, such as the implementations in Haskell:

-- Haskell
lucas :: Int -> Integer
lucas 0 = 2
lucas 1 = 1
lucas n = lucas (n - 2) + lucas (n - 1)

And in Erlang, this also holds true:

% Erlang
-module(lucascalc).
-export([lucas/1]).

lucas(0) -> 2;
lucas(1) -> 1;
lucas(N) -> lucas (N - 2) + lucas (N - 1).

Simple, easy to understand and best of all, no if statements.  But, instead of focus on this debate, I’d like to propose another which strikes closer to this functional programmers heart, the “Anti-For Campaign”.  This is simply to say that we should create and use composable functions instead of explicit for loops.  This is actually an old post I had written months ago and until now had been unfinished, but now with some inspiration, it’ll finally be done.

What and Why?

Before you throw all sorts of questions asking what and why, let me instead ask a question.  When you’re writing a loop, ask yourself the question, “What am I accomplishing in this loop?”  Chances are, it might be one of the following:

  • Query (Map, Filter, etc)
  • Aggregation (Sum, Count, etc)
  • Perform some side effect

If you’re doing more than one of those in a single loop, then well, you’re probably doing too much.  In fact, Martin Fowler’s Refactoring site has a refactoring called “Split Loop” which would solve that issue.  It is better for future refactorings and readability if we keep those loops pointed to do one thing, and one thing only.  Better yet, we could rid ourselves of that loop altogether, and that’s what we’ll focus on here.

Looking at first two bullet points, you’ll notice most of LINQ is indeed built around those two to be able to query data as well as aggregate.  The final bullet point, we perform some sort of side effect, perhaps writing to a file, printing to the console, or even perhaps sending messages. 

So, what’s my problem with them?  My problem is that it focuses more on the How instead of the What.  Let’s look at a quick example down below of what I mean.  First, we’ll attempt to find all prime numbers under 100 using C# as an example language.  First in the How:

static bool IsPrime(int i) {
    var lim = Math.Sqrt(i);
    
    Func<int, bool> check = null;
    check = j =>
        j > lim || (i % j != 0 && check(j + 1));
        
    return check(2);
}

static void Main(string[] args) {
    var numbers = Enumerable.Range(1, 100);
    var output = new List<int>();

    foreach(var number in numbers)
        if(IsPrime(number)) output.Add(number);
}

The problem is that if we then want to compose another operation, well, it’s really hard to do inside of these for loops.  We’re too focused on the how at this point.  Instead, getting to know generics and lazy evaluation, in .NET 2.0 and beyond, we were able to write generic functions to take advantage of some functional constructs.  This will give us a more declarative style that we can now focus on the what.

static IEnumerable<T> Filter<T>(
    this IEnumerable<T> items,
    Func<T, bool> predicate) {
    
    foreach(var item in items)
        if(predicate(item))
            yield return item;
}

static void Main(string[] args) {
    var numbers = Enumerable.Range(1, 100);
    
    var primes = items.Filter(x => IsPrime(x));
}

Of course we realize that LINQ already has such constructs built in, so we could rewrite the entire code above in just one statement.

var primes = Enumerable.Range(1, 100)
    .Where(x => IsPrime(x));

And what’s better is that it is composable that we could do other operations such as aggregations (sum, count, etc) without much additional code:

var primesCount = Enumerable.Range(1, 100)
    .Where(x => IsPrime(x))
    .Count();

And there you have it.  We not only have a query, but also an aggregation.  Try doing that with those non-composable loops!  Justin Etheredge has a nice writeup as well recently on the subject.

Coping Strategies

Functional languages tend to deemphasize the use of such constructs.  In fact, Haskell has neither a for loop nor a while loop, and languages such as F# and OCaml have limited support for such constructs in terms of no break and continue.  We tend to look at those two in particular with suspicion due to the fact that it cannot return a value and instead it mutates state in some fashion.  With that in mind, how do we cope with the fact that those aren’t available to us?  Above I showed a basic concept of a filter instead of an explicit loop, but what about some other considerations?

Some things we might want to consider with some links to some of my previous posts on the subject:

In fact, many times that people could consider using explicit recursion could instead use a fold to aggregate the data which then cuts out the issue of tail call optimization.  By truly understanding the goals of LINQ as well as the concepts of functional programming, we can realize that most of the looping that we do can indeed be replaced by the above, outside of side effects of course.

Now What About Those Side Effects?

Is there a place where we draw the line and say that explicit loops are ok?  Eric Lippert was recently asked about the reasoning of the lack of the ForEach extension method on IEnumerable<T>.  His response was that he was philosophically opposed to such an endeavor as the whole approach is to cause a side effect.  As IEnumerable<T> collections are immutable, he doesn’t believe it makes as much sense because you wouldn’t be side effecting the collection itself.  Not only that, but introducing closures can complicate object lifetimes and all sorts of potential reference issues.

What about me?  I understand his concerns, and in C#, I can certainly see where he is coming from.  However, in F# we have such constructs readily available to us in the iter and iteri functions as shown below in F# Interactive:

> let flip f y x = f x y
- [1..10]
-   |> List.map((*) 2)
-   |> List.filter(flip (%) 3 >> (=) 0)
-   |> List.iter(printfn "%d");;
6
12
18
> [1..10]
-   |> List.map((*) 2)
-   |> List.filter(flip (%) 3 >> (=) 0)
-   |> List.iteri(printfn "%d\t%d");;
0       6
1       12
2       18

Outside of logging, writing to the console and such are rare in functional programming, so once again, I can certainly understand the concern.

Conclusion

I hope by going through some basic scenarios that we will indeed question our code the next time we see that we are writing that explicit loop with a for and a while.  With a tool chest filled with such functions as transforming every item, to filtering content, to aggregating data and so on, we can realize that we can create composable solutions instead of creating mutable collections or mutable variables and aggregating to them which are not as much.  So, come and join me in the “Anti-For Campaign”.

This entry was posted in C#, Erlang, F#, Functional Programming, Haskell. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Matt Warren

    Matt,

    Good article, thanks for that, it ties in with the whole “Functional Approach” that I’m trying to use.

    Just one thing, your devlicio.us pop-up on the left-hand side of the screen always stays out. So it block the the first 5-6 characters of about 10 lines of text, making it hard to read the article. I’m using firefox if that help.

    Cheers

    Matt

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Paks

    Absolutely, it should be in there by default.

    Matt

  • http://www.kitiara.org Paks

    Matt,

    Don’t you think it’s time for “flip” to be in the core library? It’s so useful and simple.

    Great articles, keep them comming!

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @John,

    Right, I meant to correct that, sorry but just got back from vacation.

    Matt

  • John

    Hi Matt,
    Thanks for this great post. One minor edit – in the C# example, the line shown below is missing a paren.

    j > lim || (i % j != 0 && check(j + 1);

    I believe the line should be

    j > lim || (i % j != 0 && check(j + 1));

    Most of the veteran C# coders no doubt caught your meaning for for a language newb like me, I had to take the second look. Keep up the great articles!

  • http://devlicio.us/blogs/anne_epstein/default.aspx Anne Epstein

    Matt,
    Thanks so much for this explanation-I hadn’t really thought about for loops in this way, and it makes a lot of sense… kudos for explaining it in a way that those of us without functional programming experience (yet) can grok. I’m going to start looking at my for loops with a much more critical eye from now on…

  • http://weblogs.asp.net/bleroy Bertrand Le Roy

    @Matt: got it. I guess F# being alien to me didn’t help me understand what you meant. I suppose I would have grokked it more easily with a jQuery example for instance :)

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Bertrand

    You mean the iter? Sure, it is just another way of doing foreach, but using as I said the use of it is rather rare. The important part is the ability to pipeline several operations together and then iterate over the results, which is something you would have to do as a separate operation. To me, it makes more sense just to write it this way in F#. In C#, I still advocate for normal foreach statements.

    Matt

  • http://weblogs.asp.net/bleroy Bertrand Le Roy

    I’m with you on the querying and aggregation but that last example looks just silly to me: isn’t iteri just another way of writing foreach?