Mark Needham

Thoughts on Software Development

F# vs C# vs Java: Functional Collection Parameters

with 17 comments

I wrote a post about a month ago on using functional collection parameters in C# and over the weekend Fabio and I decided to try and contrast the way you would do this in Java, C# and then F# just for fun.

Map

Map evaluates a high order function on all the elements in a collection and then returns a new collection containing the results of the function evaluation.

Given the numbers 1-5, return the square of each number

Java

int[] numbers = { 1,2,3,4,5};
for (int number : numbers) {
    System.out.println(f(number));
}
 
private int f(int value) {
    return value*value;
}

C#

new List<int> (new[] {1, 2, 3, 4, 5}.Select(x => x*x)).ForEach(Console.WriteLine);

F#

[1..5] |> List.map (fun x -> x*x) |> List.iter (printfn "%d");;

Filter

Filter applies a predicate against all of the elements in a collection and then returns a collection of elements which matched the predicate.

Given the numbers 1-5, print out only the numbers greater than 3:

Java

int[] numbers = { 1,2,3,4,5};
for (int number : numbers) {
    f(number);
}
 
private void f(int value) {
    if(value > 3) {
        System.out.println(value);
    }
}

C#

new List<int> { 1,2,3,4,5}.FindAll(x => x > 3).ForEach(Console.WriteLine);

F#

[1..5] |> List.filter (fun x -> x > 3) |> List.iter (printfn "%d");;

Reduce

Reduce applies a high order function against all the elements in a collection and then returns a single result.

Given a list of numbers 1-5, add them all together and print out the answer

Java

int sum = 0;
int[] numbers = { 1,2,3,4,5};
for (int number : numbers) {
    sum += number;
}
System.out.println(sum);

C#

Console.WriteLine(new[] {1, 2, 3, 4, 5}.Aggregate(0, (accumulator, x) => accumulator + x));

F#

[1..5] |> List.fold_left (+) 0 |> printfn "%d";;

In Summary

I was surprised that we could achieve these results in relatively few lines of Java. The C# and F# versions are still more concise but the Java version isn’t too bad. The Apache Commons Library has a class which allows you to write these in a functional way but the need to use anonymous methods means it’s not as clean as what you can achieve in C# and F#.

I think there is still a bit of a mindset switch to make from thinking procedurally about these things to thinking in a way that allows you to make the most of functional programming concepts.

Keeping the code as declarative as possible and reducing the amount of state in our code are the most obvious things I have learned so far from playing with F#.

Be Sociable, Share!

Written by Mark Needham

January 19th, 2009 at 7:24 pm

Posted in .NET,Java

Tagged with , , ,

  • Pingback: Dew Drop - January 19, 2009 | Alvin Ashcraft's Morning Dew()

  • Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #268()

  • The first extension class I wrote was this:

    public static class IEnumerableExtensions
    {
    public static IEnumerable Each
    (this IEnumerable collection, Func action)
    {
    foreach (T item in collection)
    {
    yield return action(item);
    }
    }

    public static void Each(this IEnumerable collection, Action action)
    {
    foreach (T item in collection)
    {
    action(item);
    }
    }
    }

    This allows you to write the first two C# examples more concisely:

    new[] { 1, 2, 3, 4, 5 }.Select(x => x * x).Each(Console.WriteLine);

    new[] { 1, 2, 3, 4, 5 }.Where(x => x > 3).Each(Console.WriteLine);

  • Looks like the site software removed my angle brackets. I’m sure you can figure out what’s missing!

  • Hi Mark.

    I’m a C# guy so I have a few suggestions about the C# code. Here’s my solution to the first two methods Map/Filter.

    Enumerable.Range(1, 5).Select(x => x * x).All(x => { Console.WriteLine(x); return true; });
    Console.WriteLine();
    Enumerable.Range(1, 5).Where(x => x > 3).All(x => { Console.WriteLine(x); return true; });

    The little problem with your methods and those of Rik Hemsley posted in comment is that they create a List or int[]. They allocates memory just to iterate over some int values. In C# we can use Enumerable.Range(int start, int end) which is exactly the same as [start..end] in F#. Because IEnumerable doesn’t have ForEach, ( and I don’t want to have .ToList().ForEach() ) I’m using “my foreach” – combination of All and return true ๐Ÿ™‚

    For the 3th method I really don’t like the Aggregate method extension method of IEnumerable. So with a little bit of cheating we have :

    Console.WriteLine(Enumerable.Range(1, 5).Sum());

    ๐Ÿ™‚

  • h0tzenpl0tz

    map does NOT evaluate a high-order-function, instead map IS a high-order-function as it calls other functions over a structure.

  • Pingback: Scala, Scala, Scala « Codemountain()

  • Hi Mark, Iยดve added some comparation to Scala. Try http://raseablog.blogspot.com/2009/01/scala-scala-scala.html to see. It would be very nice to receive your visit.
    Thanks and congratulations for the simple, but very straight nice post.

  • Pingback: Ruby, Ruby, Ruby! | lucastex.com()

  • Pingback: Rick Minerich's Development Wonderland : Discoveries This Week 01/30/2009()

  • The problem with the java version is that they don’t are functional style. As your f() method does printing the stuff it is just doing a side-effect and not collecting / filtering values.

    I’d rather write those examples as gathering values in a list / colleciton / enumeration / sequence (lazy). (as you stated in your first paragraph on map). That would be much more interesting because the java version for that is much more noisy than the oder languages:

    int[] numbers = { 1,2,3,4,5};
    Collection result=new ArrayList(5);
    for (int number : numbers) {
    result.add(f(number));
    }

    private int f(int value) {
    return value*value;
    }

    Here the groovy version for map:

    1.upto(5).collect{ it*it }
    and clojure
    (map #(* % %) (range 1 5))

    THAT’s concise ๐Ÿ™‚

    If you want to print it directly:
    groovy: 1.upto(5).each{ println it*it }
    clojure: (map #(println (* % %)) (range 1 5))

    Cheers Michael

  • A

    Please don’t confuse people by using vastly different data structures in your example. Java uses an array, C# a doubly-linked list, and F# a singly-list list. Use the same data structure, say array.

    F#:

    [| 1..5 |] |> Array.map (fun x -> x * x) |> Array.iter (printfn “%i”)

  • What is the Java equivalent of Array.Parallel.init in F#? I’ll wager its absolutely *huge* because none of the infrastructure is there.

  • xx

    You put too much unnecessary code for java version

    int[] xs = {1,2,3,4,5};
    for (int x : xs)
    System.out.println(x*x);

  • Would have been nice if you use the same structure and did not create a Java version if you are not high experienced on it.

  • Griff

    As ever when looking at these code comparisons, I find myself thinking
    – when a good optimising compiler has finished, are these really that different ?
    – is writing an extremely terse single line of code actually that clever in the long term if you need
    – other people to understand it
    – to look at intermediate values when debugging
    – to assert/test valid values of the input array

  • Pingback: Functional Programming in Java – Venkat Subramaniam: Book Review at Mark Needham()